<keep-alive>
标签实现状态的保存,该标签会缓存不活动的组件实例,而不是销毁它们react-keep-alive
这个库比较重,实现原理也不难,就是笨重,断层,源码跳来跳去,真的理清楚了就好import React, { useState } from 'react'
import { render } from 'react-dom'
import KeepAlive, { AliveScope } from './KeepAlive'
function App() {
const [show, setShow] = useState(true)
return (
<div>
<button onClick={() => setShow(show => !show)}>Toggle</button>
<p>无 KeepAlive</p>
{show && <Counter />}
<p>有 KeepAlive</p>
{show && (
<KeepAlive id="Test">
<Counter />
</KeepAlive>
)}
</div>
)
}
....
render(
<AliveScope>
<App />
</AliveScope>,
document.getElementById('root')
)
DOM
元素会储存在AliveScope
组件中,所以它不能被卸载react-keep-alive
AliveScope
组件做了什么事情export class AliveScope extends Component {
nodes = {}
state = {}
keep = (id, children) =>
new Promise(resolve =>
this.setState(
{
[id]: { id, children }
},
() => resolve(this.nodes[id])
)
)
render() {
return (
<Provider value={this.keep}>
{this.props.children}
{Object.values(this.state).map(({ id, children }) => (
<div
key={id}
ref={node => {
this.nodes[id] = node
}}
>
{children}
</div>
))}
</Provider>
)
}
}
{this.props.children}
KeepAlive
组件的源码import React, { Component, createContext } from 'react'
const { Provider, Consumer } = createContext()
const withScope = WrappedCompoennt => props => (
<Consumer>{keep => <WrappedCompoennt {...props} keep={keep} />}</Consumer>
)
@withScope
class KeepAlive extends Component {
constructor(props) {
super(props)
this.init(props)
}
init = async ({ id, children, keep }) => {
const realContent = await keep(id, children)
this.placeholder.appendChild(realContent)
}
render() {
return (
<div
ref={node => {
this.placeholder = node
}}
/>
)
}
}
export default KeepAlive
withScope
是一个高阶组件,将KeepAlive组件传入,返回一个新的组件,这里使用了装饰器,@withScope.其实最终export default 的是withScope(KeepAlive)