mirror of
https://github.com/ZiuChen/ZiuChen.github.io.git
synced 2025-08-18 07:29:33 +08:00
docs: React note update
This commit is contained in:
parent
559c69f64d
commit
10a1434616
@ -4630,6 +4630,166 @@ immutablejs库的底层原理和使用方法:[React系列十八 - Redux(四)st
|
|||||||
|
|
||||||
connect函数是`react-redux`提供的一个高阶函数,它返回一个高阶组件,用于将store中的state/dispatch映射为组件的props
|
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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
:::
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user