现在,更改值m(TheDemo的状态),组件树的 struct 改变,v(TheChild的状态)将重置为初始值3.

我想要的是:在更改值m的同时,保持值v不变.

https://codesandbox.io/s/cool-waterfall-if1v0z?file=/index.js

import React, { StrictMode, useState } from "react";
import { createRoot } from "react-dom/client";

function TheDemo() {
  const [m, setM] = useState(true);
  const child = <TheChild />;
  return (
    <div style={{ fontFamily: "monospace" }}>
      <button onClick={() => setM(!m)}>m = {+m}</button>
      {m ? <b>{child}</b> : <span>{child}</span>}
    </div>
  );
}

function TheChild() {
  const [v, setV] = useState(3);
  return <button onClick={() => setV(v + 1)}>v = {v}</button>;
}

const root = createRoot(document.getElementById("root"));
root.render(
  <StrictMode>
    <TheDemo />
  </StrictMode>
);

也许这是个X-Y问题?原始问题是我想要允许用户更改页面布局,将子代_0从Parent_1移动到Parent_2.

这个演示被简化了,我有很多嵌套的子组件,而提升所有状态几乎是不可能的.

陶渊明的 comments 解决了这个问题,react docs link here.

推荐答案

正如在Preserving and Resetting State中所指出的,Reaction将组件的状态与其在DOM中的位置及其HTML标记(或者,更一般地说,与DOM树 struct )相关联.如果这些改变中的一个改变,则在改变的分支101中重置状态.在您的例子中,位置保持不变,但更改了HTML标记.

修复它的最简单方法(在本例中)是保留HTML<span>标记,并基于m的真实性将其style{}(或null)更改为{ fontWeight: 'bold' }:

<span style={ m ? {fontWeight: 'bold'} : null }>{child}</span>

如果您正在寻找一种更通用的机制(这只是一个简化的示例),您有几个其他选项可以在Reaction中保持状态:

  • 将状态提升到父组件中,该组件在m次更改时不会重新呈现,并通过props 向下传递状态
  • 使用React.context.提升状态的原理与提升状态相同,不同之处在于,无论有多少层深,都可以使用钩子进入状态,而不必进行props 钻取(将props 添加到每个中间父级)
  • use a state management solution. Jotai, Recoil, XState, Redux, Rematch, Zustand (the list is not comprehensive). I've placed Jotai first because you literally just need to replace React.useState() with Jotai.useAtom() and you're good to go 2.
    All state management solutions have a way to set a boundary on the context using that state (typically a Provider), so you can have multiple instances of the same state (e.g: in a list rendering example, where you'd want each list item and all of its children to use their own context).

1 - there is an exception: you can change the position in DOM without losing state by using :key (and keeping the same tag/component)
2 - at least in the case you presented; more complex data sharing might require more complex solutions; I'd say Jotai is good at hiding its own complexity, but does have a few gotchas.

Javascript相关问答推荐

Angular 拦截器错误处理删除方法问题

事件错误:类型错误:无法读取未定义的属性(读取stopPropagation)

Angular material 表多个标题行映射

在分区内迭代分区

是什么原因导致此Angular 16电影应用程序中因类型错误而不存在属性?

我不知道为什么setwritten包装promise 不能像我预期的那样工作

Angular material 拖放堆叠的牌副,悬停时自动展开&

如何将Map字符串,布尔值转换为{key:string;value:bo布尔值;}[]?<>

你怎么看啦啦队的回应?

并不是所有的iframe都被更换

如何在使用rhandsontable生成表时扩展数字输入验证?

Rxjs流中生成IMMER不能在对象上操作

从另一个数组中的对应行/键值对更新数组中的键值对对象

为什么云存储中的文件不能公开使用?

有效路径同时显示有效路径组件和不存在的路径组件

构建器模式与参数对象输入

如何使用[ModelJSON,ArrayBuffer]调用tf.loadGraphModelSync

在JavaScript中将Base64转换为JSON

通过解构/功能组件接收props-prop验证中缺少错误"

当达到高度限制时,如何裁剪图像?使用html和css