Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Share parent state between child components' states?

Learning React, I'm building a simple Calculator. Components model is:

- Calculator
  - Sliders (input[ref=cars])
  - Dashboard (p {this.state.cars})

Sliders is component with set of inputs, that should be transfered to Dashboard via parent Calculator state.

My goal is to make state value in Dashboard change on Sliderss input component change.

var Calculator = React.createClass({
  getInitialState: function() {
    return {
      cars: 0
    };
  },
  render: function () {
    return (
      <div className="calculator">
        <Sliders
          cars={this.state.cars}
        />
        <Dashboard
          cars={this.state.cars}
        />
      </div>
    )
  }
});

var Dashboard = React.createClass({
  getInitialState:function () {
    return {
      cars: this.props.cars
    }
  },
  render: function () {
    return (
      <div>
        <h1>Dashboard</h1>
        <p>Cars: {this.state.cars}</p>
      </div>
    )
  }
})

var Sliders = React.createClass({
  getInitialState: function() {
    return {
      cars: this.props.cars
    };
  },
  handleInput: function () {
    var state = {
      cars: this.refs.cars.value
    }
    this.setState(state);
  },
  render: function () {
    return (
      <div className="sliders">
        <input type="text" ref="cars" onChange={this.handleInput} value={this.state.cars}/>
      </div>
    )
  }
})

As I've got, handleInput() is trigged, so state for Sliders is set. However, it's NOT "transfered" to parent Calculator's state as 'cars'. So, Calculator's state is not updated => Dashboard state is not udpated too.

How to share Calculator's parent state between Sliders and Dashboard?

I know, there are plenty of similar questions on SO, however it's hard to find the specific helpful case, especially when you're complete noob in React. So, sorry for duplicating.

like image 890
f1nn Avatar asked Dec 01 '25 15:12

f1nn


2 Answers

Components don't share state. The state of one component can become the props of another component though.

In your case, cars should be the state of Calculator, and Slide and Dashboard should only retrieve cars as props. If the input changes, Sliders should notify Calculator about the change so that it can update its state and rerender (which causes Sliders and Calculator to update as well):

var Calculator = React.createClass({
  getInitialState: function() {
    return {
      cars: 0
    };
  },

  onUpdate: function (cars) {
    this.setState({cars});
  },

  render: function () {
    return (
      <div className="calculator">
        <Sliders
          cars={this.state.cars}
          onUpdate={this.onUpdate}
        />
        <Dashboard
          cars={this.state.cars}
        />
      </div>
    )
  }
});

var Dashboard = React.createClass({
  render: function () {
    return (
      <div>
        <h1>Dashboard</h1>
        <p>Cars: {this.props.cars}</p>
      </div>
    )
  }
})

var Sliders = React.createClass({
  handleInput: function (event) {
    this.props.onUpdate(event.target.value);
  },

  render: function () {
    return (
      <div className="sliders">
        <input type="text" ref="cars" onChange={this.handleInput} value={this.props.cars}/>
      </div>
    )
  }
})

As few components as possible should have state and state should be as high up in the tree as possible. See also Props in getInitialState Is an Anti-Pattern

like image 165
Felix Kling Avatar answered Dec 04 '25 04:12

Felix Kling


In React you want to have one or several "smart" components, that handle state and "dumb" components. The "smart" components transfer the state down to the "dumb" component. The also inject event handlers, like in your case a handler for changing the amount of cars. Your calculator is your smart component. It should also have a function to handle the state change.

handleCarsChange: function( newAmount ) {
  this.setState({ cars: newAmount });
},

Also don't make your initial state from props (more Information). Props are made to change, use them directly in your render function like so:

var Dashboard = React.createClass({
  render: function () {
    return (
      <div>
        <h1>Dashboard</h1>
        <p>Cars: {this.props.cars}</p>
      </div>
    )
  }
});

Or with the React 14 component function syntax:

var Dashboard = function(props) {
    return (
      <div>
        <h1>Dashboard</h1>
        <p>Cars: {props.cars}</p>
      </div>
    );
};

Last but not least give the Sliders component a handler function to deal with the state change:

<Sliders
  cars={this.state.cars}
  handleCarsChange={this.handleCarsChange}
/>

And change the handleInput function in the Slider component:

handleInput: function(value) {
  this.props.handleCarsChange(this.refs.cars.value);
},
like image 37
Herku Avatar answered Dec 04 '25 05:12

Herku



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!