Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/453.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 我是不是偶然创造了一个全球国家?_Javascript_Reactjs_State - Fatal编程技术网

Javascript 我是不是偶然创造了一个全球国家?

Javascript 我是不是偶然创造了一个全球国家?,javascript,reactjs,state,Javascript,Reactjs,State,我正在构建一个React web应用程序,该应用程序分为多个组件,可通过以下方式访问: 我现在正在更改其中一个组件中的状态,以触发使用新数据重新渲染: this.setState({ data: editedJson }); 到目前为止还不错,但当我现在切换到另一个选项卡/组件时,this.state.data也发生了变化-为什么会发生这种情况?组件之间是否共享状态 编辑:这是一个MVCE,您可以在其中更改B中的状态,也可以在A中更改: 导入该JSON文件时,似乎正在创建一个内存版本的

我正在构建一个React web应用程序,该应用程序分为多个组件,可通过以下方式访问:

我现在正在更改其中一个组件中的状态,以触发使用新数据重新渲染:

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对答案进行了一些细化更新。