简体   繁体   中英

React TypeScript - Component properties not being updated when parent state is changed

This issue is in React using TypeScript I have an array of components (Text inputs) sitting in my state. I also have an array of strings in my state that define the placeholder text of each component. Each component refers to the array of placeholder string from the state, at its corresponding index.

When I update a string within the placeholders array (using setState), the components do not update. Where am I going wrong? Or have I misunderstood how states/props work.

Thank you!

I have simplified the code a lot, to highlight the issue. Code:

interface IState {
  inputComponents: IResponseOption[];
  test_placeholder: string;
}
interface IResponseOption {
  Component: JSX.Element;
  InputValue: string;
}

class NewMultiQuestion extends React.Component<IProps, IState> {

    constructor(props: any){
        super(props);
        if (this.props.location.props) {
          this.state = { 
            inputComponents: [],
            test_placeholder: "TESTING"
          }
        }
    }

    componentDidMount() {      
      this.generateInputElems();
    }

    generateInputElems() {
      var createdInputOptions: IResponseOption[] = [];

      for (var i = 0; i < 5; i++) {
        var newInput: IResponseOption = {
          Component: (
            <div key={i}>
              <TextInput key={i} id={i + ""}  value="" placeholder={this.state.test_placeholder} hoverText={this.state.test_placeholder} />
            </div>
          ),
          InputValue: ""
        }
        createdInputOptions.push(newInput);
      }
      this.setState({inputComponents: createdInputOptions});
    }

    changeState() {
      this.setState({test_placeholder: "Did it change?!"});
    }

    public render() {

      let responseInputs = Object.keys(this.state.inputComponents).map((key)  => {
        return (this.state.inputComponents[key].Component);
      });

      return (

        <div>  
          {responseInputs}
        </div>
      );   
    }
}

export default NewMultiQuestion;

Firstly, the input elements are only generated when the component is mounted. They aren't re-built when the state updates, you'd have to call generateInputElems() again after changing test_placeholder in the state. That's not ideal, since state changes shouldn't be in response to other state changes, but to things like user action or responses from API calls.

Secondly, you shouldn't be storing entire components in the state. Just the store the data needed to render them, then build the components during the render, eg

render() {
    return(
        <div>
            {this.state.inputComponents.map((input, i) => (
                <div key={i}>
                  <TextInput id={i + ""}  value="" placeholder={this.state.test_placeholder} hoverText={this.state.test_placeholder} />
                </div>
            ))}
        </div>
    );
}

That way when the placeholder state value changes, they'll be re-rendered with the new placeholder prop value.

Also for arrays of components only the containing element needs the key. And it's usually not a good idea to use the array index as the key, if the list changes (elements added/removed) then you'll get buggy behaviour if the key is the index. Best to find some unique value to identify each array element.

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