如何强制重新安装React组件?

时间:2016-03-04 09:25:10

标签: javascript reactjs

假设我有一个具有条件渲染的视图组件:

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

MyInput看起来像这样:

class MyInput extends React.Component {

    ...

    render(){
        return (
            <div>
                <input name={this.props.name} 
                    ref="input" 
                    type="text" 
                    value={this.props.value || null}
                    onBlur={this.handleBlur.bind(this)}
                    onChange={this.handleTyping.bind(this)} />
            </div>
        );
    }
}

让我们说employed是真的。每当我将其切换为false而其他视图呈现时,只会重新初始化unemployment-duration。另外unemployment-reason预先填充了job-title的值(如果在条件更改之前给出了值)。

如果我将第二个渲染例程中的标记更改为:

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

似乎一切正常。看起来React只是没有分散'职称'和'失业原因'。

请告诉我我做错了什么......

4 个答案:

答案 0 :(得分:118)

更改组件的键。

<Component key="1" />
<Component key="2" />

组件将被卸载,并且由于密钥已更改,因此将安装新的Component实例。

修改:记录在You Probably Don't Need Derived State

  

当密钥更改时,React将创建一个新的组件实例,而不是更新当前的组件实例。键通常用于动态列表,但在这里也很有用。

答案 1 :(得分:78)

可能发生的事情是React认为在渲染之间只添加了一个MyInputunemployment-duration)。因此,job-title永远不会被unemployment-reason取代,这也是交换预定义值的原因。

当React执行diff时,它将根据key属性确定哪些组件是新组件,哪些组件是旧组件。如果代码中没有提供这样的密钥,它将生成自己的密钥。

你提供的最后一个代码片段起作用的原因是因为React基本上需要更改父div下所有元素的层次结构,我相信这会触发所有孩子的重新呈现(这就是为什么有用)。如果您将span添加到底部而不是顶部,则前面元素的层次结构将不会更改,并且这些元素不会重新呈现(并且问题会出现坚持)。

这是官方React documentation所说的:

  

当孩子们被洗牌时(如在搜索结果中)或者如果新组件被添加到列表的前面(如在流中),情况变得更加复杂。在这些情况下,必须在渲染过程中保持每个孩子的身份和状态,您可以通过为每个孩子分配一个密钥来唯一地识别每个孩子。

     

当React协调键控子项时,它将确保任何具有键的子项将被重新排序(而不是被破坏)或被销毁(而不是重用)。

您应该可以通过向父key或所有div元素提供唯一的MyInput元素来解决此问题。

例如:

render(){
    if (this.state.employed) {
        return (
            <div key="employed">
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div key="notEmployed">
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

OR

render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput key="title" ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <MyInput key="reason" ref="unemployment-reason" name="unemployment-reason" />
                <MyInput key="duration" ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

现在,当React执行差异时,它会看到divs不同并将重新呈现它,包括它的所有&#39;儿童(第1个例子)。在第二个示例中,差异将在job-titleunemployment-reason上成功,因为它们现在具有不同的密钥。

你当然可以使用你想要的任何键,只要它们是唯一的。

2017年8月更新

为了更好地了解密钥在React中的工作方式,我强烈建议您阅读我对Understanding unique keys in React.js的回答。

2017年11月更新

此更新应该在不久前发布,但现在不推荐使用ref中的字符串文字。例如,ref="job-title"现在应该是ref={(el) => this.jobTitleRef = el}(例如)。有关详细信息,请参阅我对Deprecation warning using this.refs的回答。

答案 2 :(得分:5)

在视图中使用setState更改州的employed属性。这是React渲染引擎的示例。

 someFunctionWhichChangeParamEmployed(isEmployed) {
      this.setState({
          employed: isEmployed
      });
 }

 getInitialState() {
      return {
          employed: true
      }
 },

 render(){
    if (this.state.employed) {
        return (
            <div>
                <MyInput ref="job-title" name="job-title" />
            </div>
        );
    } else {
        return (
            <div>
                <span>Diff me!</span>
                <MyInput ref="unemployment-reason" name="unemployment-reason" />
                <MyInput ref="unemployment-duration" name="unemployment-duration" />
            </div>
        );
    }
}

答案 3 :(得分:0)

我正在为我的应用程序开发Crud。这就是我做到的作为我的依赖项的方式。

print(df[cols].lt(0).any())
b     True
c    False
dtype: bool

print (df[cols].lt(0).any().reindex(df.columns, fill_value=False))
a    False
b     True
c    False
dtype: bool

其中有一些React钩子