0

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;

1 Answer 1

1

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, e.g.

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Ahh okay, thanks for the reply! That was helpful. I will restructure the way I am doing things and I'll see how I go. Cheers!
I followed your advice and made an array in the state that contains my components info. It's a much better way and make way more sense, thank you! One more question though. In regards to your last point about assigning a Key value, what would you suggest the best way of doing that would be in my situation?
Nevermind, I just added a 'key' property to my array of Field data and initialized this when creating the field data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.