pourmesomecode
pourmesomecode

Reputation: 4368

React re-rendering a component on prop update

How I think/understood was that react components update whenever their props or state change.

So I declare my variable:

let percentage = {
  width: '10%',
};

and have a setInterval function running to change that variable after so long:

setInterval(function() {
  percentage = {
    width: '50%',
  };
}, 5000);

and below this I render my component:

Meteor.startup(() => {
  render((
    <Router>
      <div>
        <Nav />
        <Route exact path="/" render={() => <Start percentage={percentage} />} />
        <Route path="/app" component={App} />
        <Modal />
      </div>
    </Router>
  ), document.getElementById('render-target'));
});

Where I display the percentage in another file that looks like:

export default class Start extends Component {
  render() {
    return (
      <div className="home">
        <div className="meter orange">
          <span style={this.props.percentage} />
        </div>
      </div>
    );
  }
}

My component never updates though, I have put a console.log into the setInterval function and get the update variable back but it never refreshes my component.

Have I misunderstood how props updates work?

Upvotes: 2

Views: 825

Answers (1)

Ethan Brown
Ethan Brown

Reputation: 27292

The parameters passed to a component are copied by value, not reference. So when you render the outermost component, you're passing the current value of percentage into the Start component:

<Start percentage={percentage} />

From the perspective of the Start component, its property never changes, even though the variable that provided its initial value is.

You can't be clever and try to get around this with an object that contains a property percentage either...because the object (the parameter itself) won't change, only its properties.

So what's a poor programmer to do?

It's a bit misleading to say that a component updates when its properties change; components actually update when they're re-rendered. Very often, this happens because the enclosing (parent) component's state changes (or its been re-rendered) and it will be passing new props down to the inner component. The solution in your case is to make percentage part of the state of the enclosing component. So you would have something like this:

class Parent extends Component {
  constructor(props, ...args) {
    super(props, ...args)
    this.state = { percentage: { width: '0%' } }
    setInterval(() => this.setState({ percentage: { width: '50%' } }), 5000)
  }
  render() {
    return <Start percentage={this.state.percentage} />
  }
}

It's technically correct that a component updates when its props change; however, the only way to change its props is to re-render it! Props are read-only inside a component. Which is why I say it's misleading (or incomplete) to think about prop changes driving component re-rendering.

Upvotes: 4

Related Questions