如何重置包含所有可传递状态的反应组件?

Posted

技术标签:

【中文标题】如何重置包含所有可传递状态的反应组件?【英文标题】:How can I reset a react component including all transitively reachable state? 【发布时间】:2014-03-12 01:39:38 【问题描述】:

我偶尔会有想要重置的概念上有状态的 react 组件。理想的行为相当于删除旧组件并读取新的原始组件。

React 提供了一个方法setState,它允许设置组件自己的显式状态,但不包括浏览器焦点和表单状态等隐式状态,它也排除了其子项的状态。捕捉所有这些间接状态可能是一项棘手的任务,我更愿意严格而彻底地解决它,而不是对每一个新的令人惊讶的状态进行打地鼠游戏。

是否有 API 或模式可以做到这一点?

编辑:我做了一个简单的例子来演示this.replaceState(this.getInitialState()) 方法并将它与this.setState(this.getInitialState()) 方法进行对比:jsfiddle - replaceState 更健壮。

【问题讨论】:

【参考方案1】:

key 属性添加到元素并从父元素控制其值的方法可以正常工作。这是一个如何使用组件进行自我重置的示例。

键在父元素中控制,但更新键的函数作为道具传递给主元素。这样,重置表单的按钮可以驻留在表单组件本身中。

const InnerForm = (props) => 
  const  resetForm  = props;
  const [value, setValue] = useState('initialValue');

  return (
    <>
      Value: value
      <button onClick=() =>  setValue('newValue'); >
        Change Value
      </button>
      <button onClick=resetForm>
        Reset Form
      </button>
    </>
  );
;

export const App = (props) => 
  const [resetHeuristicKey, setResetHeuristicKey] = useState(false);
  const resetForm = () => setResetHeuristicKey(!resetHeuristicKey);
  return (
    <>
      <h1>Form</h1>
      <InnerForm key=resetHeuristicKey resetForm=resetForm />
    </>
  );
;

【讨论】:

【参考方案2】:

为需要重新初始化的元素添加key 属性,每次与元素相关联的propsstate 更改时都会重新加载它。

key=new Date().getTime()

这是一个例子:

render() 
  const items = (this.props.resources) || [];
  const totalNumberOfItems = (this.props.resources.noOfItems) || 0;

  return (
    <div className="items-container">
      <PaginationContainer
        key=new Date().getTime()
        totalNumberOfItems=totalNumberOfItems
        items=items
        onPageChange=this.onPageChange
      />
    </div>
  );

【讨论】:

或者你可以添加一个简单的整数计数器变量作为键【参考方案3】:

为确保您提到的隐式浏览器状态和子级状态被重置,您可以在render 返回的根级组件中添加key attribute;当它发生变化时,该组件将被丢弃并从头开始创建。

render: function() 
    // ...
    return <div key=uniqueId>
        children
    </div>;

没有重置单个组件本地状态的快捷方式。

【讨论】:

只是出于好奇,当您说“组件将被丢弃并从头开始创建”时,您是否意味着虚拟 DOM 将被丢弃并从头开始创建,但 DOM 更新仍将基于差异算法? @nimgrg 不,真实的 DOM 元素也将被重新创建。 (虚拟 DOM 已经在每次渲染时重新创建,所以如果你想保留真实 DOM,在这种情况下不要设置 key。) @EamonNerbonne 在 React 0.8 上,键仅用于区分数组中的兄弟元素,并且在根处被忽略。见github.com/facebook/react/issues/590。 这似乎是旧版本的旧答案。这种技术是否仍然适用于 React 16+ 版本?更新的文档似乎没有提到这样的事情。还是我错过了什么? 有没有办法从组件内部做到这一点,而无需外部传递 key prop?【参考方案4】:

您实际上应该避免使用replaceState,而是使用setState

文档说replaceState“可能会在未来版本的 React 中被完全删除”。我认为它肯定会被删除,因为replaceState 并不真正符合 React 的哲学。它有助于让 React 组件开始感觉有点像瑞士刀。 这不利于 React 组件的自然增长,即变得更小、更有针对性。

在 React 中,如果你不得不在泛化或专业化上犯错:瞄准专业化。作为推论,您的组件的状态树应该具有一定的简约性(不过,如果您正在搭建一个具有品牌影响力的新产品,则可以巧妙地打破此规则)。

无论如何,这就是你的做法。类似于上面 Ben 的(已接受)答案,但像这样:

this.setState(this.getInitialState());

另外(就像 Ben 也说过)为了重置“浏览器状态”,您需要删除该 DOM 节点。利用 vdom 的力量并为该组件使用新的 key 属性。新的渲染将替换该组件。

参考:https://facebook.github.io/react/docs/component-api.html#replacestate

【讨论】:

如果当前状态包括任何不在初始状态的属性,这将不起作用。虽然我不认为这是一个很好的“状态”,但除非你能以某种方式阻止它,否则我想避免令人惊讶的破坏。我可以接受在某些情况下崩溃的重置,但不能巧妙地破坏状态的重置。 不确定我是否关注。你是说这不等于this.replaceState?因为它是。 @williamle8300 如果在调用getInitialState() 之间的组件生命周期中的某个位置(例如,在 onClick 处理程序中)添加新属性以声明状态,它们将不等效。在这种情况下,该新属性在第二个 getInitialState() 之后仍然存在。 @Graham 我认为向getInitialState 中尚未声明的组件引入新状态是不好的做法。就像在函数顶部的 JS 函数中声明所有变量一样。旁注:Ben Alpert 的解决方案与我的几乎相同……而且他是 React 的官方维护者! 恐怕函数 getInitialState() 以及答案已被弃用。有更新就好了。

以上是关于如何重置包含所有可传递状态的反应组件?的主要内容,如果未能解决你的问题,请参考以下文章

反应上下文不断重置

React 子组件在父组件中更新状态后如何将其重置回原始状态

重置状态反应

如何使用字符串或状态动态切换反应组件?

Maven:如果它们已经是可传递的,如何删除它们?

反应:通过更改键重新安装后,对子组件的引用为空