gpt4 book ai didi

javascript - 为什么 getDerivedStateFromProps 不允许使用状态更新重新渲染? componentWillReceiveProps 不是问题 - ReactJS

转载 作者:行者123 更新时间:2023-12-04 11:04:05 25 4
gpt4 key购买 nike

我正在尝试从 componentWillReceiveProps 转移到 getDerivedStateFromProps ,在某些情况下,我是成功的,但是当案例是将 Prop 附加到现有状态时,事情开始变得不一样了。当对组件的状态进行更新时,状态会发生变化(并且组件在更新后也会发生变化),但仍会呈现先前的状态。使用 getDerivedStateFromProp 而不是 componentWillReceiveProps 时会发生一些奇怪的事情。 似乎该方法不能很好地处理“内部”更改。在下面的示例中,我在 Child 上有 getDerivedStateFromProp 并且它可以工作,但因为只是渲染 Prop 。在一个更简单的示例中也观察到了这种行为,其中我没有任何子组件并且只是呈现状态更改。
下面的代码显示了一个子组件,用于打印/显示 props 接收到的数据,同时使用删除数据处理程序(从子组件交互中删除存储在 Parent 的数据)。使用 getDerivedStateFromProps() 时我无法访问 this.state并且 prevState 并不意味着相同,因为状态是累积的。当我从子组件中删除数据时,不会更新子组件的 Prop (使用 componentWillReceiveProps 时可以)。所以,我找不到替代我的 UNSAFE_componentWillReceiveProps 的方法。
组件WillReceiveProps:


UNSAFE_componentWillReceiveProps(nextProps){
this.setState({
data: [...this.state.data,...nextProps.data]
})
}

getDerivedStateFromProps:
   static getDerivedStateFromProps(nextProps,state) {

if (!isEqual(nextProps.data, state.data)) {
return {
data: [...state.data, ...nextProps.data]
};
}
return null;
}


按预期工作的原始代码(在父组件上的 getDerivedStateFromProps 之前)
DataConsole - 父组件:
export class DataConsole extends Component {
// Used for unsubscribing when our components unmount
unsub = null;

static defaultProps = {
data: [],
};

constructor(props) {
super(props);
this.state = {
data: [],
};

this.handleTableRowClick = this.handleTableRowClick.bind(this);
}


UNSAFE_componentWillReceiveProps(nextProps){
this.setState({
data: [...this.state.data,...nextProps.data]
})
}

handleTableRowClick(key) {
console.log(
"handleTable",
key,
this.state.data[key],
this.state.data.length
);
const e = this.state.data.splice(key, 1)
//console.log("remove?", e , this.state.data.length)

this.setState({
undoDataRemove: e
});
}


render() {
return (
<div>
<Container
fluid
style={{ paddingLeft: 0, paddingRight: 0 }}
className="DataContainer"
>
<Row noGutters>
<Col sm={8} className="ConsoleTable">
<div>
<DataViewer
data={this.state.data}
rowClickHandler={this.handleTableRowClick}
/>
</div>

...




DataViewer - 子组件
import isEqual from "react-fast-compare";
...

export class DataViewer extends Component {
static defaultProps = {
data: [],
};

constructor(props){
super(props)
this.state={data: []}
}


componentDidUpdate() {
console.log("DataViewer updated");
}

static getDerivedStateFromProps(nextProps, prevProps) {

console.log(nextProps, prevProps)
if (!isEqual(nextProps.data, prevProps.data)) {
return {
data: nextProps.data
};
}
return null;
}


render() {
return (
<div className={"TableData"}>
<Table responsive="lg" striped borderless hover>
<tbody>
{this.state.data.map((elem, ids) => {
if (!isEmpty(elem)) {
return (
<tr key={ids} onClick={() => this.props.rowClickHandler(ids)}>
<td>{ids + 1}</td>
{Object.keys(elem).map(function (value, idx) {
return (
<td key={idx}>
{value}:{elem[value]}
</td>
);
})}
</tr>
);
} else {
return null;
}
})}
</tbody>
</Table>
</div>
);
}
}


最佳答案

您的代码中存在导致您的问题的错误,它与 getDerivedStateFromProps 无关和 UNSAFE_componentWillReceiveProps .
故障线是这样的:

const e = this.state.data.splice(key, 1) 
它改变了 this.state.data无需调用 setState .永远不要那样做。唯一允许您对 this.state 进行任何更改的方法通过 this.setState或者通过从 getDerivedStateFromProps 返回要合并到状态的东西,而不是任何其他方式。
为了更轻松地应对状态树深处的变化,不可变库可以派上用场。 immer目前在该类别中名列前茅。使用 immer ,可以修改 state任何你想要的方式,只要你把它包装成 produce使用模式 this.setState(produce(this.state, newState => { /* change newState here */ })) 调用:
import produce from 'immer';

// ...

this.setState(produce(this.state, newState => {
const e = newState.data.splice(key, 1);
newState.undoDataRemove = e;
}));
希望,这可以提供帮助。

关于javascript - 为什么 getDerivedStateFromProps 不允许使用状态更新重新渲染? componentWillReceiveProps 不是问题 - ReactJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67527000/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com