react|react hooks 和 vue3 不使用状态管理工具实现全局响应

前言
说到状态管理工具,前端人都知道比如 vuexredux,它们的主要作用就是存、读、改某些全局状态的数据,实现全局响应。不过,使用这些工具一般有个所谓最佳实践的原则,那就是能不使用,就不使用。或者说,除非不使用它的时候,某些功能无法优雅的实现,否则就最好不用。
这怎么理解呢?举个例子,我们搞一个简单点的网站全局中、英文切换,正常情况下,语言类型变量定义在全局,并能够在站内 header 组件上进行切换,那么组件结构可能是:

//...

此时,假设不使用全局的状态管理工具,语言类型变量数据和切换功能,维护在 header 这一层。那么不进行全局状态管理,必定需要把语言变量在很多组件中传递。
同时还有个问题,假设产品说,不仅仅需要在 header 切换语言,而且还在某一两处组件上也能切换,那么问题就更麻烦了点。
尽管如此,这个场景在业务上也并不算复杂,为了一个单薄的语言切换变量在全局响应,就多安装 vuex 包,写 store.js ,还定义 mutation,这样好像是合理的,好像又不合理。不合理的原因就很明显了,功能单薄,框架却偏重。
React 的 createContext/useContext 和 vue3 的 provide/inject
所以,相对简单的全局响应场景下,vuexredux 之类的状态管理工具就显得不太合适,而合适的方式,自然就追求减负、和全局响应功能的体量相对应的。现在下面具体说说目前可以有的两种方式。
1. React hooks 的 createContext/useContext 【react|react hooks 和 vue3 不使用状态管理工具实现全局响应】操作方法:先在根组件比如 App.tsx 文件中定义需要全局响应的 state,及其 setState 方法,这俩东西分别 create 一个 Context(createContext),再在 stateContext.Provider 标签上传 statesetState.Provider 标签上传 setState,在需要读写的后代组件上拿到这两个 Context,就能在后代组件上读取、修改全局数据:
//App.tsx import React, { createContext, FC, Dispatch, SetStateAction, useState } from 'react'; import HelloWorld from './components/HelloWorld'interface StateInf { name: number; } const defaultState: StateInf = { name: 111 }export const stateContext = createContext(defaultState) export const setStateContext = createContext< Dispatch> | undefined >(undefined)const App: FC = () => { const [state, setState] = useState(defaultState)const changeState = () => { // 在根组件修改全局name变量 setState({...state, name: 222}) } return ({state.name} ) } export default App

// HelloWorld.tsx import React, { useContext, FC, Dispatch, SetStateAction } from 'react'; import { stateContext, setStateContext } from '../App'const HelloWorld: FC = () => { const state = useContext<{name: number}>(stateContext) const setState = useContext | undefined >(setStateContext)const changeState = () => { if ( setState ) { // 此处传函数参数,实现后代组件修改全局state setState(state => { return { ...state, name: 222 } }) } }return ( {state.name}) } export default HelloWorld

2. vue3 的 provide/inject 其实 vue3 这个方式在文档上也提到过,类似的,将需要修改的 data 及其修改方法,分别通过一个 provide 传下去,比 React 的操作要更简洁一些:
// App.vue

// HelloWorld.vue

结语
  1. 这两种操作自我感觉很舒适,也挺推荐,在一定程度上可以替代一部分状态管理工具的能力;
  2. 至于react低版本,以及vue2能否实现,我尝试结果是暂不能实现的,有兴趣的兄弟可以去试一下,如果实现了,可以在评论区指点一下,贴下关键代码。此处所谓的“实现”,是类似上面两种方案,不仅在全局定义状态,并且上层的修改能响应到下层,同时下层还能修改,响应到上层。

    推荐阅读