ReactJS error: make sure to pass up the same props that your component's constructor was passed

Viewed 10550

I am learning the "clear" ReactJS (i.e. it is not JSX). This is my simple code:

(() => {
    class List extends React.Component{
        constructor({tag, attributes, items}){
            super({tag, attributes, items})
            this.tag = tag
            this.attributes = attributes
            this.items = items
        }
        render(){
            return React.createElement(this.props.tag, this.props.attributes, items.map(
                (n, i) => new React.createElement(ListItem, 
                    { attributes: { ...n.attributes, key: i }, value: n.value })))
        }
    }

    class ListItem extends React.Component{
        constructor({attributes, value}){
            super({attributes, value})
            this.attributes = attributes
            this.value = value
        }
        render(){
            return React.createElement("li", this.props.attributes, this.props.value)
        }
    }

    const items = [
        { attributes: null, value: "A" },
        { attributes: null, value: "B" },
        { attributes: null, value: "C" },
        { attributes: null, value: "D" },
        { attributes: null, value: "E" }
    ]

    const root = document.getElementById("root")

    ReactDOM.render(new React.createElement(List, { tag: "ul", attributes: null, items }), root)
})()

Pay attention please: I put into the super the same parameters that I get in the component's constructor. Also I use key for li elements. But I get such errors:

Warning: List(...): When calling super() in List, make sure to pass up the same props that your component's constructor was passed.

Warning: Each child in an array or iterator should have a unique "key" prop.

Check the render method of List.

in ListItem (created by List)

in List

Warning: ListItem(...): When calling super() in ListItem, make sure to pass up the same props that your component's constructor was passed. Warning: ListItem(...): When calling super() in ListItem, make sure to pass up the same props that your component's constructor was passed. Warning: ListItem(...): When calling super() in ListItem, make sure to pass up the same props that your component's constructor was passed. Warning: ListItem(...): When calling super() in ListItem, make sure to pass up the same props that your component's constructor was passed. Warning: ListItem(...): When calling super() in ListItem, make sure to pass up the same props that your component's constructor was passed.

What did I do wrong?

2 Answers

You need use a single variable say props for example as a paramter of constructor function. Then pass it to the super. The below code fixed all warnings.

class List extends React.Component {
  constructor(props) {
    super(props);
    this.tag = props.tag;
    this.attributes = props.attributes;
    this.items = props.items;
  }
  render() {
    return React.createElement(
      this.props.tag,
      this.props.attributes,
      items.map(
        (n, i) =>
          new React.createElement(ListItem, {
            attributes: { ...n.attributes, key: i },
            value: n.value
          })
      )
    );
  }
}

class ListItem extends React.Component {
  constructor(props) {
    super(props);
    this.attributes = props.attributes;
    this.value = props.value;
  }
  render() {
    return React.createElement("li", this.props.attributes, this.props.value);
  }
}

const items = [
  { attributes: null, value: "A" },
  { attributes: null, value: "B" },
  { attributes: null, value: "C" },
  { attributes: null, value: "D" },
  { attributes: null, value: "E" }
];

const root = document.getElementById("root");

ReactDOM.render(
  new React.createElement(List, { tag: "ul", attributes: null, items }),
  root
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
 <div id="root"></div>

Official doc says Class components should always call the base constructor with props.

When I look at the source:

const hasMutatedProps = instance.props !== newProps;
warningWithoutStack(
    instance.props === undefined || !hasMutatedProps,
      '%s(...): When calling super() in `%s`, make sure to pass ' +
      "up the same props that your component's constructor was passed.",
      name,
      name,
  );

It seems react checks if the props object it received in the constructor function is same object that you passed to base class using super() or not. And in your code, it is of-course not the same. What you are passing to the super({attributes, value}) for example totally a different object. Because in JS:

{a: 1, b: 2} === {a:1, b:2} // false
{a: 1, b: 2} !== {a:1, b:2} // true

you can use Destructuring inside render method

class List extends React.Component{
    constructor(props){
        super(props).....

    render(){
        const {tag, attributes, items} = this.props
        return React.....
Related