Che*_*het 38 javascript reactjs
我有一个<StatefulView>维护内部状态的简单组件.我有另一个组件<App>切换是否<StatefulView>呈现.
但是,我希望<StatefulView>在安装/卸载之间保持内部状态.
我想我可以实例化组件<App>,然后控制它是否渲染/挂载.
var StatefulView = React.createClass({
getInitialState: function() {
return {
count: 0
}
},
inc: function() {
this.setState({count: this.state.count+1})
},
render: function() {
return (
<div>
<button onClick={this.inc}>inc</button>
<div>count:{this.state.count}</div>
</div>
)
}
});
var App = React.createClass({
getInitialState: function() {
return {
show: true,
component: <StatefulView/>
}
},
toggle: function() {
this.setState({show: !this.state.show})
},
render: function() {
var content = this.state.show ? this.state.component : false
return (
<div>
<button onClick={this.toggle}>toggle</button>
{content}
</div>
)
}
});
Run Code Online (Sandbox Code Playgroud)
这显然不起作用,<StatefulView>每个切换都会创建一个新的.
这是一个JSFiddle.
有没有办法在卸载后挂起到同一个组件,以便可以重新安装?
ama*_*ann 39
我也在考虑这个问题.
我把我的尝试放在这个回购中:react-keep-state.
对我来说,最合适的解决方案如下:
import React, { Component, PropTypes } from 'react';
// Set initial state
let state = { counter: 5 };
class Counter extends Component {
constructor(props) {
super(props);
// Retrieve the last state
this.state = state;
this.onClick = this.onClick.bind(this);
}
componentWillUnmount() {
// Remember state for the next mount
state = this.state;
}
onClick(e) {
e.preventDefault();
this.setState(prev => ({ counter: prev.counter + 1 }));
}
render() {
return (
<div>
<span>{ this.state.counter }</span>
<button onClick={this.onClick}>Increase</button>
</div>
);
}
}
export default Counter;
Run Code Online (Sandbox Code Playgroud)
请参阅repo以获得有关此内容的一些讨论(以及使用更高阶组件的另一种解决方案).
Che*_*het 19
好.因此,在与一群人交谈之后,事实证明无法保存组件的实例.因此,我们必须将其保存在其他地方.
1)保存状态最明显的地方是父组件.
这不是我的选择,因为我试图从类似UINavigationController的对象推送和弹出视图.
2)您可以将状态保存在其他地方,如Flux商店或某些全局对象.
这对我来说也不是最好的选择,因为这将是一场噩梦,追踪哪些数据属于导航控制器等的哪个视图.
3)传递一个可变对象来保存和恢复状态.
这是我在React的Github回购中发表各种问题门票时发现的一个建议.这似乎是我的方法,因为我可以创建一个可变对象并将其作为道具传递,然后使用相同的可变道具重新渲染相同的对象.
我实际上修改了一点以使其更加通用,我使用的是函数而不是可变对象.我认为这更加理智 - 不可变数据总是比我更好.这是我正在做的事情:
function createInstance() {
var func = null;
return {
save: function(f) {
func = f;
},
restore: function(context) {
func && func(context);
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,getInitialState我正在为组件创建一个新实例:
component: <StatefulView instance={createInstance()}/>
Run Code Online (Sandbox Code Playgroud)
然后在StatefulView我只需要保存和恢复componentWillMount和componentWillUnmount.
componentWillMount: function() {
this.props.instance.restore(this)
},
componentWillUnmount: function() {
var state = this.state
this.props.instance.save(function(ctx){
ctx.setState(state)
})
}
Run Code Online (Sandbox Code Playgroud)
就是这样.它对我来说非常好用.现在我可以将组件视为实例:)
嗯,你可以使用localStorage,或者AsyncStorage如果是React Native.
React Web
componentWillUnmount() {
localStorage.setItem('someSavedState', JSON.stringify(this.state))
}
Run Code Online (Sandbox Code Playgroud)
那天晚些时候或者2秒后:
componentWillMount() {
const rehydrate = JSON.parse(localStorage.getItem('someSavedState'))
this.setState(rehydrate)
}
Run Code Online (Sandbox Code Playgroud)
反应原生
import { AsyncStorage } from 'react-native'
async componentWillMount() {
try {
const result = await AsyncStorage.setItem('someSavedState', JSON.stringify(this.state))
return result
} catch (e) {
return null
}
}
Run Code Online (Sandbox Code Playgroud)
那天晚些时候或者2秒后:
async componentWillMount() {
try {
const data = await AsyncStorage.getItem('someSavedState')
const rehydrate = JSON.parse(data)
return this.setState(rehydrate)
} catch (e) {
return null
}
}
Run Code Online (Sandbox Code Playgroud)
您还可以Redux在呈现时使用数据并将其传递给子组件.您可能会受益于研究serializing状态和Redux createStore函数的第二个参数,该函数用于重新初始化初始状态.
请注意,这JSON.stringify()是一项昂贵的操作,因此您不应该在按键等操作.如果您有疑虑,请调查去抖动.
在渲染之间缓存状态的一种简单方法是利用模块在您正在处理的文件上导出表单闭包的事实。
使用useEffect钩子,您可以指定组件卸载时发生的逻辑(即更新在模块级别关闭的变量)。这是有效的,因为导入的模块被缓存,这意味着导入时创建的闭包永远不会消失。我不确定这是否是一个好的方法,但在文件仅导入一次的情况下有效(否则将cachedState在默认渲染组件的所有实例之间共享)
var cachedState
export default () => {
const [state, setState] = useState(cachedState || {})
useEffect(() => {
return () => cachedState = state
})
return (...)
}
Run Code Online (Sandbox Code Playgroud)
小智 5
对于那些只是在2019年或以后阅读本文的人,其他答案中已经给出了很多细节,但是在这里我要强调以下几点:
如果您希望能够在保持状态的同时卸载和挂载,则需要存储计数App并通过 props 传递计数。
(执行此操作时,您应该在 内部调用切换函数App,您希望更改数据的功能与数据一起使用)。
我将修改您的小提琴以使其功能正常并用它更新我的答案。
| 归档时间: |
|
| 查看次数: |
31189 次 |
| 最近记录: |