简体   繁体   中英

How to update state of parent by passing a function as props to its children

I have a parent component A which will have a child component B. The parent component can have multiple similar child components. I want to process the data of this child component in the parent component hence I pass a functions as props to the child component. Now whenever a change is made in the child component I want to re-render all the components from the parent. I have a state in the parent called componentList which is an array of type object. Each object will have data about one child component. This gives me syntax error and if I change and try something else it gives me undefined value for componentList.

export class Parent extends React.Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      componentList: []
    };
  this.onClick = this.onClick.bind(this);
  this.onDataChange = this.onDataChange.bind(this);
 }

public onDataChange(index: number) {
  return function(data: Data) {
    this.setState({
      this.state.componentList[index].name = data.name;
    });
  };
}

In child component I am updating the name onChange as below:

interface Props {
 name?: string;
 age?: number;
 onDataChange: (data: Data) => void;
}

export class Child extends React.Component<Props> {
 constructor(props: Props) {
  super(props);
  this.state = {};
  this.onNameChange = this.onNameChange.bind(this);
}

public onNameChange(event) {
  this.props.onDataChange({
    name: event.target.value,
    age: this.props.age
  });
}

Getting error: "TypeError: Cannot read property 'componentList' of undefined"

Are you doing binding of onDataChange function before sending to the props?

export class parentClass extends Component{
    constructor(props){
        super(props);
        this.onDataChange=this.onDataChange.bind(this);
    }
}*/

If not, this keyword in onDataChange invocation points to the wrong context

also replace

this.setState({
    this.state.componentList[index].name = data.name;
});

with something like

this.setState({componentList:newComponentList});

As my comment seemed to help you, I've decided to post an answer. Your onDataChange function is returning another function to be invoked by the child.

public onDataChange(index: number) {
  return function(data: Data) { // A function gets returned
    this.setState({
      this.state.componentList[index].name = data.name;
    });
  };
}

and inside the child you are binding the reference of the this keyword to the this keyword of the child:

this.onDataChange=this.onDataChange.bind(this);

which is generally not wrong, but you want to update the state on the parent, therefore you need a reference to the parent this.

This can be easily achieved by simply changing the return "value" of your onDataChange function.

public onDataChange(index: number) {
  // An arrow function always set the this reference to where it's declared correctly,
  // therefore this inside the function will reference the parent this.
  return (data: Data) => {
    this.setState({
      this.state.componentList[index].name = data.name;
    });
  };
}

What's also obsolete then is: this.onDataChange = this.onDataChange.bind(this); inside your parent constructor.

It might be helpful to read up on this topic over at MDN - Arrow functions .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM