如何在 React 组件上强制重新安装

How to force remounting on React components?

本文关键字:重新安装 组件 React      更新时间:2023-09-26

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

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

我的输入看起来像这样:

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 只是无法区分"职称"和"失业原因"。

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

更改组件的键。

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

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

记录在 你可能不需要派生状态:

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

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

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

您提供的最后一个代码片段之所以有效,是因为 React 本质上需要更改父div下所有元素的层次结构,我相信这将触发所有子元素的重新渲染(这就是它工作的原因)。如果将span添加到底部而不是顶部,则前面元素的层次结构不会更改,并且这些元素不会重新呈现(并且问题将持续存在)。

以下是官方 React 文档的内容:

当孩子被打乱(如在搜索结果中)或将新组件添加到列表的前面(如在流中)时,情况会变得更加复杂。在这些情况下,每个子项的标识和状态必须在渲染通道中维护,您可以通过为其分配一个键来唯一标识每个子项。

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

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

例如:

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

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是不同的,并将重新渲染它,包括它的所有子项(第一个示例)。在第二个示例中,差异将在job-titleunemployment-reason上取得成功,因为它们现在具有不同的键。

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

<小时 />

2017 年 8 月更新

为了更好地了解键在 React 中的工作原理,我强烈建议阅读我在 React.js 中理解唯一键的答案。

<小时 />

2017 年 11 月更新

此更新应该在不久前发布,但现在已弃用在 ref 中使用字符串文本。例如,ref="job-title"现在应该改为ref={(el) => this.jobTitleRef = el}(例如)。有关更多信息,请参阅我对使用 this.refs 的弃用警告的回答。

在视图中使用 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>
        );
    }
}

我正在为我的应用程序开发 Crud。这就是我的做法 得到反应 作为我的依赖。

import React, { useState, setState } from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import firebase from 'firebase';
// import { LifeCrud } from '../CRUD/Crud';
import { Row, Card, Col, Button } from 'reactstrap';
import InsuranceActionInput from '../CRUD/InsuranceActionInput';
const LifeActionCreate = () => {
  let [newLifeActionLabel, setNewLifeActionLabel] = React.useState();
  const onCreate = e => {
    const db = firebase.firestore();
    db.collection('actions').add({
      label: newLifeActionLabel
    });
    alert('New Life Insurance Added');
    setNewLifeActionLabel('');
  };
  return (
    <Card style={{ padding: '15px' }}>
      <form onSubmit={onCreate}>
        <label>Name</label>
        <input
          value={newLifeActionLabel}
          onChange={e => {
            setNewLifeActionLabel(e.target.value);
          }}
          placeholder={'Name'}
        />
        <Button onClick={onCreate}>Create</Button>
      </form>
    </Card>
  );
};

那里的一些反应钩子