docs: React note update

This commit is contained in:
ZiuChen 2023-04-28 16:06:54 +08:00
parent 559c69f64d
commit 10a1434616

View File

@ -4630,6 +4630,166 @@ immutablejs库的底层原理和使用方法[React系列十八 - Redux(四)st
connect函数是`react-redux`提供的一个高阶函数它返回一个高阶组件用于将store中的state/dispatch映射为组件的props
下面手写一个connect函数实现和库提供的connect一样的映射功能
下面一步一步手写一个connect函数实现和库提供的connect一样的映射功能
首先完成基本的代码搭建connect函数接收两个参数`mapStateToProps` `mapDispatchToProps`返回一个高阶组件
所谓高阶组件,就是传入一个类组件,返回一个增强后的新的类组件:
```tsx
// connect.js
import { PureComponent } from 'react'
export default function connect(mapStateToProps, mapDispatchToProps) {
return (WrapperComponent) =>
class InnerComponent extends PureComponent {
render() {
return <WrapperComponent {...this.props} />
}
}
}
```
其中,`mapStateToProps``mapDispatchToProps`都是函数,函数入参是`state``dispatch`,返回一个对象,键值对对应`prop <=> state/dispatch调用`
我们导入store并且从store中获取到state和dispatch传入`mapStateToProps``mapDispatchToProps`随后将得到的键值对以props形式传递给WrapperComponent
这样新组件就可以拿到这些状态与dispatch方法我们可以在`componentDidMount`中监听整个store当store中的状态发生改变时强制执行re-render
```tsx {9}
// connect.js
import { PureComponent } from 'react'
import store from '../store'
export default function connect(mapStateToProps, mapDispatchToProps) {
return (WrapperComponent) =>
class InnerComponent extends PureComponent {
componentDidMount() {
store.subscribe(() => this.forceUpdate())
}
render() {
const state = mapStateToProps(store.getState())
const dispatch = mapDispatchToProps(store.dispatch)
return <WrapperComponent {...this.props} {...state} {...dispatch} />
}
}
}
```
上述代码能够正常工作但是显然每次store内state发生改变都re-render是不明智的因为组件可能只用到了store中的某些状态
那些组件没有用到的其他状态发生改变时组件不应该也跟着re-render这里可以做一些优化
```ts {10,14-16}
// connect.js
import { PureComponent } from 'react'
import store from '../store'
export default function connect(mapStateToProps, mapDispatchToProps) {
return (WrapperComponent) =>
class InnerComponent extends PureComponent {
constructor(props) {
super(props)
this.state = mapStateToProps(store.getState())
}
componentDidMount() {
store.subscribe(() => {
this.setState(mapStateToProps(store.getState()))
})
}
render() {
const state = mapStateToProps(store.getState())
const dispatch = mapDispatchToProps(store.dispatch)
return <WrapperComponent {...this.props} {...state} {...dispatch} />
}
}
}
```
经过优化后每次store.state发生变化会触发setState由React内部的机制来决定组件是否应当重新渲染
如果组件依赖的state发生变化了那么React会替我们执行re-render而不是每次都强制执行re-render
进一步地,我们可以补充更多细节:
- 当组件卸载时解除监听
- `store.subscribe`会返回一个`unsubscribe`函数 用于解除监听
- 解除与业务代码store的耦合
- 目前的store来自业务代码 更优的做法是从context中动态获取到store
- 应当提供一个context Provider供用户使用
- 就像`react-redux`一样使用connect前需要将App用Provider包裹并传入store
至此就基本完成了一个connect函数
::: code-group
```tsx [connect.js]
// connect.js
import { PureComponent } from 'react'
import { StoreContext } from './storeContext'
export function connect(mapStateToProps, mapDispatchToProps) {
return (WrapperComponent) => {
class InnerComponent extends PureComponent {
constructor(props, context) {
super(props)
this.state = mapStateToProps(context.getState())
}
componentDidMount() {
this.unsubscribe = this.context.subscribe(() => {
this.setState(mapStateToProps(this.context.getState()))
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
const state = mapStateToProps(this.context.getState())
const dispatch = mapDispatchToProps(this.context.dispatch)
return <WrapperComponent {...this.props} {...state} {...dispatch} />
}
}
InnerComponent.contextType = StoreContext
return InnerComponent
}
}
```
```tsx [storeContext.js]
// storeContext.js
import { createContext } from 'react'
export const StoreContext = createContext(null)
export const Provider = StoreContext.Provider
```
```tsx [App.jsx]
// App.jsx
import React, { Component } from 'react'
import store from './store'
import Counter from './cpns/Counter'
import { Provider } from './hoc'
export default class App extends Component {
render() {
return (
<Provider value={store}>
<div>
<h1>React Redux</h1>
<Counter />
</div>
</Provider>
)
}
}
```
:::