Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.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
Reactjs 从子组件更新状态_Reactjs - Fatal编程技术网

Reactjs 从子组件更新状态

Reactjs 从子组件更新状态,reactjs,Reactjs,看看这个应用程序。有一个按钮列表。我很难向你们解释这个问题,所以亲自看看这个应用程序,把它看作是一个挑战。这真的是一个小应用程序,用来演示我在使用react时遇到的问题。这不是一个基本的东西 单击按钮时,它旁边的布尔值将变为false。起初,这似乎很基本,但当您查看代码时,这并不容易实现。我的实际应用程序更复杂,所以我制作了一个简单的版本来演示这个问题 Expect: Click on button 1 => boolean next to it turns to false Click

看看这个应用程序。有一个按钮列表。我很难向你们解释这个问题,所以亲自看看这个应用程序,把它看作是一个挑战。这真的是一个小应用程序,用来演示我在使用react时遇到的问题。这不是一个基本的东西

单击按钮时,它旁边的布尔值将变为false。起初,这似乎很基本,但当您查看代码时,这并不容易实现。我的实际应用程序更复杂,所以我制作了一个简单的版本来演示这个问题

Expect:
Click on button 1 => boolean next to it turns to false
Click on button 2 => boolean next to it turns to false
Click on button 3 => boolean next to it turns to false

Reality:
Click on button 1 => screen goes blank

代码中的问题与状态更新有关。handle按钮需要将状态处理为:

const handleButton = (id) => {
    console.log("On button click: ", id);

    setState((state) => {
      // Update isSaved of a corresponding button to false
      const updatedState = [...state];
      const updatedIndex = updatedState.findIndex((item) => item.id === id);

      updatedState[updatedIndex] = {
        ...updatedState[updatedIndex],
        isSaved: false
      };

      return updatedState;
    });
  };
解决方案实际上是在
setState
变量中,它使用
回调
setState((latestState)=>{//do something})
并保证为每次执行提供最新的
状态


感谢您提出了一个漂亮的问题来解决。

因此,这是解决这个问题的另一种方法

但首先,我将确定现有代码中的问题,并尝试解释为什么它不起作用

我在
App.js中放置了两个
console.log
,一个在
useffect()
中,另一个在
return
语句之前:

export default function App() {
  const [state, setState] = React.useState([]);

  // Set pannels state
  React.useEffect(() => {
    console.log("useEffect executing");

    setState(
      data.map((item) => ({
        id: item.id,
        isSaved: true,
        content: <Button id={item.id} handleButton={handleButton} />
      }))
    );
  }, []);

  const handleButton = (id) => {
   ....
   ....
  }

  console.log("App Rendering");
  return (
    <div className="App">
      <button onClick={handleClick}>Try this</button>
      {state ? <Tab pannels={state} /> : null}
    </div>
  );
}
现在,如果您仔细观察
{handleButton}
是绑定到“App”的第一个呈现的函数(当然它本身就是一个函数),并且
{handleButton}
可以访问其父作用域中的
const state
,这是“App”的第一个呈现周期中的空数组[]

因此,您在“<代码> {把手按钮} /代码>中,在<代码>状态< /代码>中,它仍然有一个值[](空数组),而<代码>使用效果< /代码>正在执行。

只要
setState
useffect
内部完成,就会执行
App
的另一个渲染周期(由于本地状态更新,react会重新渲染组件)。将创建
App
的新实例及其所有嵌套成员,由
react
管理的
state
setState
除外

在第二次呈现
App
之后,您的
状态现在包含
{handleButton}
的旧实例的引用(您将属性
content
指定给
App
之前呈现的
按钮
),因此这些
{handleButton}
仍然具有
状态
值[](空数组闭包)

现在,当您单击任何
按钮时,它的
onClick
绑定到
handleButton
的旧引用,该引用的
state
值为空数组,因此当
{handleButton}
完成执行时,它将调用
setState
(由react框架提供的函数,不受重新渲染的影响)它再次将
状态设置为一个空数组。最终,按钮消失了

现在要解决这个问题,您需要在每次对
App
进行重新渲染时重新绑定
{handleButton}
的新实例。您不能记忆
{handleButton}
因为它取决于
状态
。因此,您可以将
按钮
组件的呈现委托给
选项卡
,该选项卡在每次
状态
更新后重新呈现自身

所以你可以这样做:

App.js

export default function App() {
  const [state, setState] = React.useState([]);

  // Set pannels state
  React.useEffect(() => {
    setState(
      data.map((item) => ({
        id: item.id,
        isSaved: true
      }))
    );
  }, []);

  const handleButton = (id) => {
    console.log("On button click: ", id);
    console.log(state);

    //Update isSaved of a corresponding button to false
    const updatedState = [...state];
    const updatedIndex = updatedState.findIndex((item) => item.id === id);

    updatedState[updatedIndex] = {
      ...updatedState[updatedIndex],
      isSaved: false
    };

    setState(updatedState);
  };

  return (
    <div className="App">
      <button onClick={() => handleButton(2)}>Try this</button>
      {state ? <Tab pannels={state} handleButton={handleButton} /> : null}
    </div>
  );
}
const Tab = ({ pannels, handleButton }) => {
  return (
    <div>
      List of pannels
      {pannels.map((item) => (
        <div key={item.id}>
          <Button id={item.id} handleButton={handleButton} />
          <span>{item.isSaved ? "true" : "false"}</span>
        </div>
      ))}
    </div>
  );
};
代码沙盒参考:


谢谢

看到了,你明白了。但这里我们希望选项卡具有动态内容。这并不总是按钮,这就是我们使用内容道具的原因。看看这个例子,我的沙盒是它的简单版本。你可以看到选项卡窗格包含选项卡。内容:这迫使我在这里通过内容道具!!谢谢非常感谢您!!!!您能解释一下为什么它会起作用吗?谢谢您的回答。您的示例不起作用,但可能是我的函数中有错误。抱歉,但我已经更新了它。更改
handleButton
函数中更新状态的方式所需的唯一一件事。尽管我仍在试图找出您的解决方案失败的原因oes不起作用…如果成功的话,我想分享一个解释…谢谢你很棒的解决方案。你明白了。但这里我们希望选项卡具有动态内容。它并不总是一个按钮,这就是我们使用内容道具的原因。看看这个例子,我的沙盒是它的简单版本。你可以看到选项卡窗格包含选项卡。内容:Check@Yousaf在上面的评论。我真的很感谢你的努力,能有一个像你一样热衷于分享和解决问题的开发人员真是太棒了。好吧,在这种情况下,我的另一个答案(我已经给出了两个答案)对这个问题没什么问题。
const Tab = ({ pannels, handleButton }) => {
  return (
    <div>
      List of pannels
      {pannels.map((item) => (
        <div key={item.id}>
          <Button id={item.id} handleButton={handleButton} />
          <span>{item.isSaved ? "true" : "false"}</span>
        </div>
      ))}
    </div>
  );
};