0%

React FC 有自己的 `this`

借助 valtio 为 react function component 添加 this (实际为 self)

React Class component 比较方便的一点是基于 class 和 instance, 可以保存一些状态到实例(this.state)上, 但 FC + hooks 心智负担更小, 已全面替代 class component. 但需要不停地 useState / useRef, 有没有可能也用上 this 呢?

演示

1
2
3
function Foo() {
return <div>the Foo Component</div>
}

借助 valtio 创建 FC 伴生类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { proxy, useSnapshot } from 'valtio'

class FooSelf {
store = proxy({
state1: true,
items: [] as string[],
})

someProp = false

useStore = () => {
return useSnapshot(this.store)
}

setStore = (payload: Partial<typeof this.store>) => {
Object.assign(this.store, payload)
}
}
  • 需要参与渲染的状态如 state1 items 等, 放到 FooSelf.store, 就像 class component this.state 一样
  • 不需要参与渲染的状态如 someProp, 放到 class property 上即可, 心智模型与 class compoennt 的 class property 或 FC useRef 一致.

useInitFooSelf

1
2
3
4
5
6
7
8
9
10
11
12
function useInitFooSelf() {
// 自己使用 useRef
const ref = useRef(null)
ref.current ||= new FooSelf()
return ref.current
}

// or
import { useCreation } from 'ahooks'
function useInitFooSelf() {
return useCreation(() => new FooSelf(), [])
}

使用

1
2
3
4
5
function Foo() {
const self = useInitFooSelf()
const { state1, items } = self.useStore()
return <div>the Foo Component</div>
}

这样可以

  • 减少很多 useState / useRef 代码
  • 使用 self.useStore 获取渲染状态, 使用 self.store.<prop> 读取最新状态, 设置状态用 self.setStore() , 心智模型类似 this.setState
  • 可以方便 lift state up, 比如使用 React Context FooSelfContext, 将整个 fooSelf 共享给子树