Javascript 我是不是偶然创造了一个全球国家?
我正在构建一个React web应用程序,该应用程序分为多个组件,可通过以下方式访问: 我现在正在更改其中一个组件中的状态,以触发使用新数据重新渲染:Javascript 我是不是偶然创造了一个全球国家?,javascript,reactjs,state,Javascript,Reactjs,State,我正在构建一个React web应用程序,该应用程序分为多个组件,可通过以下方式访问: 我现在正在更改其中一个组件中的状态,以触发使用新数据重新渲染: this.setState({ data: editedJson }); 到目前为止还不错,但当我现在切换到另一个选项卡/组件时,this.state.data也发生了变化-为什么会发生这种情况?组件之间是否共享状态 编辑:这是一个MVCE,您可以在其中更改B中的状态,也可以在A中更改: 导入该JSON文件时,似乎正在创建一个内存版本的
this.setState({
data: editedJson
});
到目前为止还不错,但当我现在切换到另一个选项卡/组件时,this.state.data
也发生了变化-为什么会发生这种情况?组件之间是否共享状态
编辑:这是一个MVCE,您可以在其中更改B中的状态,也可以在A中更改:
导入该JSON文件时,似乎正在创建一个内存版本的JSON文件,然后两个组件都在引用该文件。如果您按照@Christiaan在构造函数中的建议复制值(排列),那么您可以避免对原始值进行变异,这是一种糟糕的做法 更好的建议是在公共祖先中导入JSON一次,并将引用或复制的实例传递到每个选项卡。。。这取决于每个选项卡对这些数据真正需要做什么 您应该注意,每当切换选项卡时,每个选项卡都会被挂载/卸载,因此每次都会运行构造函数逻辑。如果希望状态更改保持不变,则必须将其放样到父组件,即index.js中的选项卡组件,并向每个子选项卡传递它们所需的数据 实际上有几个因素对你不利。第一个是导入是缓存的(),因此每次装入选项卡时,json导入都会返回存储在
data
中的缓存引用,并在构造函数中将该引用值保存到state.data
。第二个是你的setState
函数不是一个纯粹的函数。它只是再次复制引用,并在确实需要创建新数组时对其指向的数组进行变异,并在添加新元素之前浅层复制所有元素。下面是另一个沙盒,可以帮助说明这一点
所有组件中的json都有相同的指针,所以所有组件都访问相同的对象并更改它 要解决此问题,必须为每个组件创建全新的对象,如下所示:
constructor(props) {
super(props);
this.state = {
data: json
};
}
this.state = {
data: { ...json }
};
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);
我可以像这样复制您的问题:
constructor(props) {
super(props);
this.state = {
data: json
};
}
this.state = {
data: { ...json }
};
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);
从“React”导入React;
从“react dom”导入react dom;
从“反应选项卡”导入{Tab,Tabs,TabList,TabPanel};
导入“/styles.css”;
让json={title:“我是一个title”};
函数内容({tab}){
const[state,setState]=React.useState(json);
返回(
{tab}
{state.title}
新标题
);
功能手柄更改(e){
json={title:e.target.value};
setState(json);
}
}
函数TabNavigator(){
返回(
A.
B
);
}
const rootElement=document.getElementById(“根”);
render(,rootElement);
当您更新“全局”对象json
,然后使用它更新组件
状态时,就会出现问题。请参见handleChange
功能;我首先更新json
对象,然后用它设置新组件state
当您切换到另一个选项卡
时,将创建一个新组件,该组件将从“全局”json
对象实例化其状态,因此,该组件将与另一个选项卡
具有相同的内容。在它们之间切换时,此过程会重复
如果您删除此分配以更新状态
,则问题已解决(只需执行设置状态({title:e.target.value}
)。但您无法保留更改。若要解决此问题,建议使用React上下文
我希望这会有所帮助。提供一个代码示例来重现您的问题可能会更有帮助。至少您应该共享完整的代码。例如,在这里最好包含选项卡组件代码,以查看其设置状态的内容/位置/方式。当您的
Tabs
每TabPanel
get loaded默认情况下,由于两个组件中的状态名称相同,因此您的组件可以访问彼此的状态。更改其中一个组件中的状态名称。另一种方法是有条件地呈现选项卡面板
,只需单击选项卡
即可维护状态并使用该状态呈现选项卡面板
。另一种可能性是您使用的是同一个指针指向获取的数据。对于每个选项卡面板组件,您应该制作一个数据副本,如下所示:this.state={data:{…json}
首先,我要说的是,状态信息是本地化到组件本身的。如果不将数据显式地传递到其他组件,其他组件就无法知道状态。正如另一个组件所说,请发布一个完全可复制的示例。可能包括组件a和B第二个沙盒对我帮助很大-谢谢!C您是否可以在这行中添加硼:const[dataA,setDataA]=useState(data)
?有关如何使用它以及如何使用React的钩子的更多信息,请阅读。第二个@guzmonne。useState
是一个React钩子,用于向功能组件添加状态,它接受一个初始值并返回两个元素的数组,索引0是状态值,索引1是状态变量函数。如果语法看起来这有点可笑,因为该模式还使用数组分解来命名返回值。@MiXT4PE对答案进行了一些细化更新。