高阶组件处理Context.Consumer死亡回调

77 阅读1分钟

痛点

  • 从官网可以知道Context的使用规则
  • 项目中通过Context使用全局变量,为了功能单一原则,如用户登录信息状态加载状态、或者其他的全局变量,通过Provider提供
  • 通过Context.Consumer进行消费,使用规则如下
<MyContext.Consumer>
    {data => /** 基于context进行渲染 */}
</MyContext.Consumer>
  • 从上面就会发现问题:如果有多个context,会出现死亡回调,非常不雅观。如何处理这样的函数是需要解决的问题

解决方案

前期调研

  • 使用高阶组件的方式,通过高阶组件接收Context、Component。返回一个函数组件FC,实现包装

怎么做

  • 函数定义
function withContext<S extends any>(Context: React.Context<S>) { // 第一个参数是Context
    return function<P extends S>(Component: React.ComponentType<P>) { // 第二个参数Component
        return function(props: Omit<P, keyof S>) {
            return (
                <Context.Consumer>
                    {(data: S) =><Component {...{ ...props as any, ...data as any}} />}
                </Context.Consumer>
            )
        }
    }
}
  • 定义context
// user.tsx
const defaultValue = { isLogin: false, logout(): void };
export const UserContext = React.createContext(defaultValue)
export type UserStata = typeof defaultValue;
export class UserProvider extends React.Component<{}, UserState> {
    state = {
        ...defaultValue,
        ...{
            logout:this.logout
        }
    }
    logout = () => {
        this.setState({
            isLogin: true,
        });
    }
    render() {
        return (
            <UserContext.Provider value={this.state}>
                {this.props.children}
            </UserContext.Provider>
        )
    }
}
  • 提供全局变量
import { UserProvider } from "user.tsx";
ReactDOM.render(
    <UserProvider>
        <Login />
    </UserProvider>
)
  • 消费
// login.tsx
withContext(UserContext)(Login)

其他

注意React.Context<T>React.ComponentType<T>的使用