我正在构建一个React Web应用程序,该应用程序分为可通过react-tabs访问的多个组件:
import React from 'react';
import ReactDOM from 'react-dom';
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import a from './components/a';
import b from './components/b';
const TabNavigator = () => (
<Tabs>
<TabList>
<Tab> A </Tab>
<Tab> B </Tab>
</TabList>
<TabPanel>
<a />
</TabPanel>
<TabPanel>
<b />
</TabPanel>
</Tabs>
);
ReactDOM.render(<TabNavigator />, document.getElementById('root'));
每个选项卡都是他自己的组件/子系统,当访问该选项卡时将重新呈现该组件/子系统。在每个标签中,我都使用一个JSON文件的数据。像这样将这些数据加载到每个组件的状态:
constructor(props) {
super(props);
this.state = {
data: json
};
}
我现在正在更改组件之一的状态,以使用新数据触发重新渲染:
this.setState({
data: editedJson
});
到目前为止还不错,但是当我现在切换到另一个选项卡/组件this.state.data
时,那里也发生了变化-为什么会发生这种情况?组件之间是否共享状态?
编辑:这是一个MVCE,您可以在其中更改B中的状态,它也将在A中更改:
答案 0 :(得分:1)
似乎当您导入该JSON文件时,您正在为其创建一个内存中版本,然后两个组件都将其引用。如果按照@Christiaan的建议在构造函数中复制值(散布值),则可以避免对原始值进行变异,这是一种不好的做法。
更好的建议可能是在公共祖先中将JSON导入一次,并将引用或复制的实例传递给每个选项卡……这实际上取决于每个选项卡真正需要对该数据执行的操作。
您应该注意,每当您切换选项卡时,每个选项卡都会被挂载/取消安装,因此构造函数逻辑每次都会运行。如果您希望状态更改继续存在,则必须将其放到父组件(即index.js中的Tabs组件)中,并将所需的数据传递给每个子选项卡。
实际上有几个因素对您不利。首先是导入被缓存(explanation here)的事实,因此,每次安装选项卡时,json导入都会返回缓存的引用,该引用存储在data
中,并且在构造函数中,您将该引用值保存到state.data
。第二个问题是您的setState
函数不是一个纯粹的函数。它只是再次复制引用,并在真正要创建新数组的时候更改它指向的数组,然后在添加新元素之前浅拷贝所有元素。下面是另一个沙箱,应该可以帮助说明这一点。
答案 1 :(得分:1)
我能够像这样复制您的问题:
import React from "react";
import ReactDOM from "react-dom";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import "./styles.css";
let json = { title: "I am a title" };
function Content({tab}) {
const [state, setState] = React.useState(json);
return (
<div>
<h1>{tab}</h1>
<h2>{state.title}</h2>
<label>New Title</label>
<input type="text" value={state.title} onChange={handleChange} />
</div>
);
function handleChange(e) {
json = { title: e.target.value };
setState(json);
}
}
function TabNavigator() {
return (
<Tabs>
<TabList>
<Tab>A</Tab>
<Tab>B</Tab>
</TabList>
<TabPanel><Content name="A" /></TabPanel>
<TabPanel><Content name="B"/></TabPanel>
</Tabs>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<TabNavigator />, rootElement);
当您更新“全局”对象json
,然后使用它来更新component
状态时,就会出现问题。参见handleChange
函数;我先更新json
对象,然后使用它设置新组件state
。
当您转移到另一个tab
时,将创建一个新组件,该组件的状态将从“全局” json
对象实例化,因此,其内容与其他tab
。当您在它们之间切换时,将重复此过程。
如果您删除此分配以更新state
,那么问题就解决了(只需setState({title: e.target.value}
)。但是你不能坚持改变。为了解决这个问题,我建议使用React Context。 Here is a link to a CodeSandbox where you can see it in action。
希望对您有帮助。
答案 2 :(得分:0)
您所有组件中的json具有相同的指针,因此所有组件都可以访问同一对象并进行更改。
要解决此问题,必须为每个组件创建一个全新的对象,如下所示:
this.state = {
data: { ...json }
};