javascript - 为什么直接来自父组件的 onChange func 与通过组件的实例方法代理会导致不同的状态值?
问题描述
目标:我试图理解为什么捕获的状态值在以下两种方法之间不同。
我有一个包含输入过滤器属性数组的父状态。对于每个过滤器,都有一个onChange
回调函数,它对当前状态进行深度复制,修改value
相关元素的,并更新整个数组的状态。子组件是<FilterWrapper>
,如果相同则阻止渲染value
。这个组件最终渲染了 antdesign 库的<InputNumber>
组件。
我尝试的两种方法是:
- 只需将 onChange 函数按原样传递给
<InputNumber>
. 这不知何故导致了一个问题,因为如果输入 A 发生更改,输入 B 不知道状态是否已更改。如果稍后输入 B 发生更改,它将对旧状态值进行深度复制,因此在状态更新期间它会意外恢复输入 A 的值。 - 或者,我将 onChange 定义为的实例方法
<InputNumber>
并将其传递给<InputNumber>
. 这个函数只是onChange
从父组件运行。这会产生所需的行为。
问题是,为什么它们会产生不同的行为?在这两种情况下,如果一个输入发生更改,则在 shouldComponentUpdate 条件下另一个输入将不会呈现(因此转到的 onChange 属性<InputNumber>
不会更新)。
下面是代码。也可以在我的repo中找到。我只是使用 create-react-app 来说明这一点。
应用程序.js:
import React from 'react';
import InputWrapper from './InputWrapper';
import _ from 'lodash';
import 'antd/dist/antd.css';
class App extends React.Component {
state = {
metricValues: [
{
metric: 'METRIC_A',
value: 50,
someOtherAttribute1: true,
someOtherAttribute2: 'boo',
},
{
metric: 'METRIC_B',
value: 10,
someOtherAttribute1: true,
someOtherAttribute2: 'bla',
},
],
};
minMaxRanges = {
METRIC_A: [0, 100000],
METRIC_B: [0, 1000000],
};
render() {
const { metricValues } = this.state;
const inputFilters = ['METRIC_A', 'METRIC_B'].map((m) => {
const mv = metricValues.find((f) => f.metric === m);
const onChange = (value) => {
const newMetricValueFilters = _.cloneDeep(metricValues);
const mvCopy = newMetricValueFilters.find((f) => f.metric === m);
mvCopy.value = value;
this.setState({ metricValues: newMetricValueFilters });
};
const props = {
range: this.minMaxRanges[m],
value: mv.value,
onChange,
};
return (
<div style={{ margin: 12, display: 'flex' }} key={m}>
<div style={{ marginRight: 12 }}>{m}</div>
<InputWrapper {...props} />
</div>
);
});
return <div className="App">{inputFilters}</div>;
}
}
export default App;
InputWrapper.js:
import React from 'react';
import { InputNumber } from 'antd';
class InputWrapper extends React.Component {
shouldComponentUpdate(np, ns) {
const { value } = this.props;
// this prevents any component to render if the value hasn't changed
// I know per React's official documentation that this is not a guarantee,
// but in this case I added logs when the render function is triggered and confirmed
// render didn't execute in either cases
return np.value !== value;
}
onChange = (v) => {
const { onChange } = this.props;
onChange(v);
};
render() {
const { range, value, onChange } = this.props;
const min = range[0];
const max = range[1];
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-around',
}}
>
<div>
<InputNumber
min={min}
max={max}
style={{ width: 80 }}
value={value}
onChange={(v) => {
// if onChange from the parent is used directly, the last state
// when this component is last rendered is used
// use this for approach #1
// comment this out if we want to try approach #2
onChange(v);
// if we use this.onChange(),which calls the parent's onChange, the most recent state is used
// uncomment below for approach #2
// this.onChange(v);
}}
size="small"
/>
</div>
</div>
);
}
}
export default InputWrapper;
一些截图:
初始状态:
使用方法 1: 更改输入 A:
然后更改输入 B(输入 A 也将被还原):
使用方法2:
更改 A 然后 B 产生了预期的结果:
提前致谢!
解决方案
推荐阅读
- c++ - 无法从向量返回指针
- kubernetes - 无法在 Pod 中挂载本地目录
- java - 弹簧执行器“/auditevents”端点返回 404
- lua - Lua:未使用“math.random”生成的值
- python - Pandas:使用字典中元组的列标题和单元格值创建数据框
- java - Spring Cloud Gateway Filter Factory for Fire and Forget 模型
- php - 如果使用 andWhere(),Symfony 3.4 / createQueryBuilder 不起作用(ClassNotFoundException)
- r - RStudio 中与 Shiny 相关的问题
- flutter - 我对异步功能和屏幕上的更新信息有疑问
- javascript - 使用 localStorage 返回最后一次搜索