当 prop 改变时 React 不重新渲染组件

时间:2021-01-20 07:33:07

标签: reactjs

我有一个选择列表组件,它根据选定的选项呈现一些子项。当我在两个选项中使用不同的 props 渲染相同的组件时,问题就出现了,因为在这种情况下,组件不会使用新的 props 重新渲染。

让我澄清一下问题:我有一个选项列表,我选择选项“A”,然后在选项列表下方呈现一个文本组件,我在该文本字段中键入“错误”,然后在选项列表中选择选项“B” ,然后另一个文本字段组件消失,另一个文本字段组件呈现在选项列表的正下方。最后一个组件应该被渲染为空,但问题是它包含“错误”一词。

这是重现错误的代码的最小化版本:

import React from "react";

class TextField extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: props.value };
  }

  _onChange = (event) => {
    this.setState({ value: event.currentTarget.value });
  };

  _handleBlur = (event) => {
    this.setState({ value: event.currentTarget.value.trim() });
  };

  render() {
    const { value } = this.state;
    return (
      <div>
        <label>TextField</label>
        <input
          type="text"
          onChange={this._onChange}
          onBlur={this._handleBlur}
          value={value}
        />
      </div>
    );
  }
}

class Picklist extends React.Component {
  constructor(props) {
    super(props);
    this.state = { selectedOption: "" };
    this.options = ["Blank", "A", "B"];
  }

  // eslint-disable-next-line consistent-return
  _handleSelectorCallback = (newOption) => {
    this.setState({ selectedOption: newOption.currentTarget.value });
  };

  _renderChildren(selectedOption) {
    if (!selectedOption) {
      return null;
    }
    if (selectedOption === "A") {
      return <TextField value="optionA"/>;
    }
    if (selectedOption === "B") {
      return <TextField value="optionB"/>;
    }
  }

  _renderOptions() {
    const { selectedOption } = this.state;
    return this.options.map((option) => (
      <option value={option} selected={selectedOption === option}>
        {option}
      </option>
    ));
  }

  render() {
    const { selectedOption } = this.state;
    return (
      <React.Fragment>
        <div>
          <label>Demo of the Error!</label>
          <select
            onChange={this._handleSelectorCallback}
            value={selectedOption}
          >
            {this._renderOptions()}
          </select>
        </div>
        {this._renderChildren(selectedOption)}
      </React.Fragment>
    );
  }
}

export default Picklist;


忽略组件写得有多糟糕,只是为了重现我遇到的错误。知道为什么没有使用新值重新渲染组件吗?

2 个答案:

答案 0 :(得分:2)

我认为发生的事情是,当你从一个 <TextField> 切换到另一个时,React 试图通过将不同的 props 传递给同一个实例来提高效率。你可以告诉 React 它们是不同的,应该通过添加一个键来重新渲染:

_renderChildren(selectedOption) {
    if (!selectedOption) {
      return null;
    }
    if (selectedOption === "A") {
      return <TextField key="A" value="optionA" />;
    }
    if (selectedOption === "B") {
      return <TextField key="B" value="optionB" />;
    }
  }

或者,您可以使 TextField 成为受控组件,这意味着它没有内部状态,并且 value/onChange fn 作为 props 传入。我编辑了您的代码和框以遵循以下模式:https://codesandbox.io/s/empty-wind-43jq4?file=/src/App.js

答案 1 :(得分:1)

我试过你的沙箱。您的 TextField 组件不会被卸载,因此它的构造函数只会被调用一次。您所做的与该组件有关的每项更改都会转到它的 componentDidUpdate 挂钩。

所以这就是你所缺少的:

componentDidUpdate() {
   if (this.state.value !== this.props.value) {
     this.setState({ value: this.props.value });
   }
}