当前位置: 首页 > 知识库问答 >
问题:

更新子组件中的不可变变量

巫马俊力
2023-03-14

App.js中有一个全局变量plyView,该变量在我的应用程序组件之外设置。

let plyViewed = 0;

function App() {

它监视棋盘游戏正在进行的移动。在黑板下面是一些导航按钮。如果您单击

这一切都很好,直到我重构!

我把导航按钮,谁的JSX代码都在App()函数中,并把它放在

我下面的代码给出了一个例子,说明我是如何使用那个plyView代码的。当有人点击导航按钮时,它会触发一个事件,触发代码更新plyView,尽管现在它不再工作了,因为它是一个道具。其余的游戏数据存储在一个名为game细节的对象中。

我将下面的plyView传递如下:

<MoveButtons
  plyViewed={plyViewed}
  // etc.
/>

下面是我的MoveList组件的缩短版本。

在我的应用程序的多个区域中使用plyView,如gameMore。我考虑过把它放在game细节对象中,但是如果作为道具传递,我仍然有game细节不可变的问题。然后,如果我将plyView设置为状态变量,它将变得异步,因此不适合用于计算。

我是不是完全错了?

export default function MoveButtons(props) {
  return (
    <Grid item xs={6}>
      <Button
        variant="contained"
        color="primary"
        size="large"
        style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
        onClick={() => {
          if (props.plyViewed > 0) {
            props.plyViewed--;
            props.board.current.setPosition(props.fenHistory[props.plyViewed]);
            props.setFen(props.fenHistory[props.plyViewed]);
            props.setSelectedIndex(props.plyViewed);
          }
        }}
      >
        <NavigateBeforeIcon />
      </Button>
      <Button
        variant="contained"
        color="primary"
        size="large"
        style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
        onClick={() => {
          if (props.plyViewed < props.fenHistory.length - 1) {
            props.plyViewed++;
            props.board.current.setPosition(props.fenHistory[props.plyViewed]);
            props.setFen(props.fenHistory[props.plyViewed]);
            props.setSelectedIndex(props.plyViewed);
          }
        }}
      >
        <NavigateNextIcon />
      </Button>
    </Grid>
  );
}

共有3个答案

仇经武
2023-03-14

然后,如果我将plyView设置为状态变量,它将变得异步,因此不适合用于计算。

我认为这是错误的,您只需要开始使用useffect

function App() {
    const [plyViewed, setPlyViewed] = useState(0);
    <MoveButtons
        plyViewed={plyViewed}
        setPlyViewed={setPlyViewed}
    />
}

export default function MoveButtons(props) {
    useEffect(() => {
        props.board.current.setPosition(props.fenHistory[props.plyViewed]);
        props.setFen(props.fenHistory[props.plyViewed]);
        props.setSelectedIndex(props.plyViewed);
    }, [props.plyViewed, props.fenHistory]);
    return (
    <Grid item xs={6}>
      <Button
        variant="contained"
        color="primary"
        size="large"
        style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
        onClick={() => {
          if (props.plyViewed > 0) {
            props.plyViewed--;
          }
        }}
      >
        <NavigateBeforeIcon />
      </Button>
      <Button
        variant="contained"
        color="primary"
        size="large"
        style={{ maxWidth: props.buttonWidth, minWidth: props.buttonWidth }}
        onClick={() => {
        if (props.plyViewed < props.fenHistory.length - 1) {
          props.plyViewed++;
        }}
      >
        <NavigateNextIcon />
      </Button>
    </Grid>
  );
端木弘方
2023-03-14

虽然我们缺少完整的图片,但听起来好像plyViewed应该是一个状态,如果使用React正确执行,异步行为不应该阻止任何计算。

很容易忽略这样一个事实,即在设置状态时,新的状态值是由我们自己同步计算的。我们可以使用相同的本地值来计算其他任何内容,异步行为根本不会影响我们。

    onClick={() => {
      if (props.plyViewed > 0) {

        // New local value computed by ourselves synchronously.
        const updatedPlyViewed = props.plyViewed - 1;

        // Set the state with the new value to reflect changes on the app.
        props.setPlyViewed(updatedPlyViewed);

        // Use the up-to-date local value to compute anything else
        props.board.current.setPosition(props.fenHistory[updatedPlyViewed]);
        props.setFen(props.fenHistory[updatedPlyViewed]);
        props.setSelectedIndex(updatedPlyViewed);
      }
    }}

这是一个非常简单的模式,有助于解决新状态值的最基本问题。

快速计算可以在渲染阶段完成。此时,最新的状态值将始终可用。如果可以很容易地从单个值计算多个状态值,就不需要同步多个状态值,就像这里的plyView

const [plyViewed, setPlyViewed] = useState(0);

// No special state or function needed to get the position value.
const position = fenHistory[plyViewed];

下面是一个交互式示例,演示如何使用简单状态在渲染阶段计算大量不同的派生信息。

// Get a hook function
const { useState } = React;

// This component only cares about displaying buttons, the actual logic
// is kept outside, in a parent component.
const MoveButtons = ({ onBack, onNext }) => (
  <div>
    <button type="button" onClick={onBack}>
      Back
    </button>
    <button type="button" onClick={onNext}>
      Next
    </button>
  </div>
);

const App = () => {
  const [fenHistory, setFenHistory] = useState(["a", "b"]);
  const [plyViewed, setPlyViewed] = useState(0);

  const position = fenHistory[plyViewed];

  const onBack = () => setPlyViewed((curr) => Math.max(curr - 1, 0));
  const onNext = () =>
    setPlyViewed((curr) => Math.min(curr + 1, fenHistory.length - 1));

  return (
    <div>
      <p>Ply viewed: {plyViewed}</p>
      <p>Fen position: {position}</p>
      <p>Fen history: {fenHistory.join(", ")}</p>
      <button
        type="button"
        onClick={() =>
          setFenHistory((history) => [...history, `new-${history.length}`])
        }
      >
        Add to fen history
      </button>

      <MoveButtons onBack={onBack} onNext={onNext} />
    </div>
  );
};

// Render it
ReactDOM.render(<App />, document.getElementById("app"));
button {
  margin-right: 5px;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
夹谷成仁
2023-03-14

您正在尝试更新从组件树中的更高级别组件传递下来的道具,这是不可能的。

您可以选择使用React的useState钩子创建状态,并向下传递值和调度程序,但不推荐这样做,因为您将在树上钻取道具。

您还可以将onClick事件(或部分事件)传递到App组件,这是对第一种方法的改进,但不是您的最佳实践。

您真正应该做的是使用React自己的上下文API或Redux来管理您的全局状态。我想这能帮到你。

 类似资料:
  • 在 redux 基本概念的不可变数据管理 中给出一些示例,演示了不可变的基本更新操作,例如,更新一个对象中一个字段,或者,在数组的末尾增加一个数据。然而,reducer 经常需要综合使用这些基本操作去处理更加复杂的任务。下面是一些你可能必须去实现的常见任务的例子。 更新嵌套的对象 更新嵌套数据的关键是必须适当地复制和更新嵌套的每个级别。这往往是那些学习 redux 一个难以理解的概念,当试图更新嵌

  • 为什么在下面的伪代码示例中,当容器更改foo.bar时,Child没有重新呈现? 即使我在修改容器中的值后调用,Child仍然显示旧值。

  • 问题内容: jQuery的 我正在发出一个AJAX请求,该请求会使用服务器的响应来更新变量()的值。这是我正在使用的代码: 问题是的值仍然是一个空字符串。我知道这不是服务器端脚本的问题,因为我会收到错误警报,或者至少得到string 。 这是一个演示问题的JSFiddle:http : //jsfiddle.net/GGDX7/ 为什么不变的价值? 纯JS 我正在发出一个AJAX请求,该请求会使用

  • 问题内容: 有没有Java原始数组的不变选择?制作一个原始数组final实际上并不能阻止人们做类似的事情 我希望数组的元素不可更改。 问题答案: 不适用于原始数组。你将需要使用列表或其他数据结构:

  • 我是reactjs的新手,我不知道如何从父组件中更改子组件的状态。下面是代码 每当对父组件中的执行时,我希望子组件接收。 有什么建议吗?

  • 问题内容: 第一个System.out打印 2 并且应该打印,而第二个System打印 65 。我已经用这种语言编程了一年多了,据我所知这是不可能发生的!有什么帮助吗? 上面的代码在两行上都显示 9 。 问题答案: 当你这样做,之前仅仅是一个参考阵列, NO 新阵列已创建并分配给。因此,当您查看自己的价值时,基本上就是查看的价值,反之亦然。只是的别名。这就是为什么在第二张照片中您得到65。 检查该