我有一个选择列表组件,它根据选定的选项呈现一些子项。当我在两个选项中使用不同的 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;
忽略组件写得有多糟糕,只是为了重现我遇到的错误。知道为什么没有使用新值重新渲染组件吗?
答案 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 });
}
}