React在prop更新上重新渲染组件

时间:2017-04-25 17:11:11

标签: javascript reactjs react-router

我的想法/理解是,只要他们的道具或状态发生变化,反应组件就会更新。

所以我宣布我的变量:

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

并且运行setInterval函数以在这么长时间后更改该变量:

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

在此之下,我渲染我的组件:

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'));
});

我在另一个文件中显示的百分比如下:

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

我的组件永远不会更新,我已将console.log放入setInterval函数并获取更新变量,但它永远不会刷新我的组件。

我是否误解了道具更新的工作原理?

1 个答案:

答案 0 :(得分:4)

传递给组件的参数由 value 复制,而不是参考。因此,当您渲染最外层组件时,您将percentage当前值传递到Start组件中:

<Start percentage={percentage} />

Start组件的角度来看,它的属性永远不会改变,即使提供其初始值的变量是。

你不能聪明,并尝试使用包含属性percentage的对象来解决这个问题...因为对象(参数本身)不会改变,只会改变它的属性。

那么一个可怜的程序员要做什么?

当一个组件的属性发生变化时,它会更新,这有点误导;组件在重新呈现时实际更新 。通常,这是因为封闭(父)组件的状态发生了变化(或者它被重新渲染),并且它会将新的道具传递给内部组件。在您的情况下,解决方案是使percentage成为封闭组件状态的一部分。所以你会有这样的事情:

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} />
  }
}

技术上正确组件在其道具改变时更新;但是,改变道具的唯一方法就是重新渲染它!道具在组件内是只读的。这就是为什么我说考虑推动组件重新渲染的道具变化是误导(或不完整)。