如何重置包含所有可传递状态的反应组件?
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
属性,每次与元素相关联的props
或state
更改时都会重新加载它。
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() 以及答案已被弃用。有更新就好了。以上是关于如何重置包含所有可传递状态的反应组件?的主要内容,如果未能解决你的问题,请参考以下文章