对于呈现两次的同一组件,React 构造函数只调用一次



我希望这个开关可以工作,但不知何故,组件<A/>的构造函数只被调用了一次。 https://codesandbox.io/s/jvr720mz75

import React, { Component } from "react";
import ReactDOM from "react-dom";
class App extends Component {
state = { toggle: false };
render() {
const { toggle } = this.state;
return (
<div>
{toggle ? <A prop={"A"} /> : <A prop={"B"} />}
<button onClick={() => this.setState({ toggle: !toggle })}>
toggle
</button>
</div>
);
}
}
class A extends Component {
constructor(props) {
super(props);
console.log("INIT");
this.state = { content: props.prop };
}
render() {
const { content } = this.state;
return <div>{content}</div>;
}
}
ReactDOM.render(<App />, document.getElementById("root"));

我已经找到了 https://codesandbox.io/s/0qmnjow1jw 解决方法。

<div style={{ display: toggle ? "none" : "block" }}>
<A prop={"A"} />
</div>
<div style={{ display: toggle ? "block" : "none" }}>
<A prop={"B"} />
</div>

我想了解为什么上面的代码不起作用

在 react 中,如果您想多次渲染相同的组件并将它们视为不同组件,那么您需要为它们提供一个独特的key。请尝试以下代码。

{toggle ? <A key="A" prop={"A"} /> : <A key="B" prop={"B"} />}

由于该三元语句在任何一种情况下都会呈现一个<A>组件的结果,当<App>的状态更新并更改toggle时,React 看到在和以前相同的位置仍然有一个<A>,但具有不同的prop道具。当 React 重新渲染时,它通过尽可能少地进行更改来实现。因此,由于这是同一类元素在同一个地方,因此 React 不需要在toggle更改时创建新元素,只需更新该<A>元素的 props。

从本质上讲,这条线

{toggle ? <A prop="A"/> : <A prop="B"/> }

相当于

<A prop={ toggle ? "A" : "B" }/>

也许更清楚地不需要创建新的<A>组件,只需更新现有组件。

那么问题就变成了您在构造函数中使用props.prop设置<A>state.content,因此state.content永远不会更新。解决此问题的最干净方法是在<A>组件的render方法中使用props.prop而不是state.content。因此,您的A类如下所示:

class A extends Component {
render() {
const { prop } = this.props;
return <div>{ prop }</div>;
}
}

如果必须获取prop道具并在<A>组件的状态下使用它,则可以使用componentDidUpdate.下面是一个示例:

class A extends Component {
constructor(props) {
super(props);
this.state = {content: props.prop};
}
componentDidUpdate(prevProps) {
if (prevProps.prop !== this.props.prop) {
this.setState({content: this.props.prop});
}
}
render() {
const { content } = this.state;
return <div>{ content }</div>
}
}

React 只会调用构造函数一次。这是预期的结果。 看起来您正在尝试根据道具更新组件 A 的状态。 你可以直接使用prop,也可以使用componentDidUpdate生命周期方法,正如Henry所建议的那样。另一种方法是使用静态方法 getDerivedStateFromProps 根据传递的 prop 更新状态。

static getDerivedStateFromProps(props, state) {
return ({
content: props.prop
});
}

最新更新