oyalhi
oyalhi

Reputation: 3984

react state is not updated/passed to child component when child component is passed as a property

I am trying to create dynamic form, so I pass some jsx elements to a child component as a property. Even though the state is being updated, the updated state is not passed to the element. Below is the code:

This is the child component which maps over the passed controls and outputs them.

class Form extends Component {
  render() {
    return (
      <div>
        {this.props.controls.map((c, i) => {
          return <React.Fragment key={i}>{c}</React.Fragment>;
        })}
      </div>
    );
  }
}

This is the App that calls the child component:

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      username: '',
      password: ''
    };

    this.controls = [
      <input
        type="text"
        onChange={this.onChangeUsername}
        value={this.state.username}
      />
    ];
  }

  componentDidUpdate() {
    console.log(this.state);
  }

  render() {
    return (
      <div className="App">
        <div className="app__group">
          <h1>This is not working</h1>
          <Form controls={this.controls} />
        </div>
        <div className="app__group">
          <h1>This is working</h1>
          <input
            type="text"
            onChange={this.onChangePassword}
            value={this.state.password}
          />
        </div>
      </div>
    );
  }

  onChangeUsername = e => {
    console.log('onChangeUsername', e.target.value);
    this.setState({ username: e.target.value });
  };

  onChangePassword = e => {
    console.log('onChangePassword');
    this.setState({ password: e.target.value });
  };
}

As an example of the unexpected behaviour, when an input passed as a property to the child component, I cannot type in the input. The state gets updated but it's is not passed to the child, thus the text does not show.

On the other hand, a standard input element works, I can type and see the output.

What am I doing wrong?

Upvotes: 0

Views: 59

Answers (1)

Prince Hernandez
Prince Hernandez

Reputation: 3721

the problem is that you are trying to make something "fixed" as something dynamic. lets go with a more functional approach and it will refresh each one of the inputs like if they are dynamic.

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      username: '',
      password: ''
    };
  }

  componentDidUpdate() {
    console.log(this.state);
  }

  render() {
    return (
      <div className="App">
        <div className="app__group">
          <h1>This is not working</h1>
          <Form controls={this.controls()} />
        </div>
      </div>
    );
  }

  controls = () => {
    return [<input
            type="text"
            onChange={this.onChangeUsername}
            value={this.state.username}
           />]
  }

  onChangeUsername = e => {
    console.log('onChangeUsername', e.target.value);
    this.setState({ username: e.target.value });
  };

  onChangePassword = e => {
    console.log('onChangePassword');
    this.setState({ password: e.target.value });
  };
}

Upvotes: 3

Related Questions