基于react-hooks的替代redux解决方案

981 阅读3分钟

背景

react hooks 已经发布很久了,相关文档已经有了大量的资源.
本文提供一个基于react-hooks的redux 替代解决方案.
PS: 没有最好的解决方案,只有最适合的解决方案.本文不完善的地方请在评论指出
项目地址 https://github.com/Tangpriest/hooks_demo

关键字

create-react-app react-hooks

初始化项目

初始化项目用的是create-react-app脚手架
为什么不用webpack自己构建? 因为懒 ......
其实是因为这不是本文讲解的重点
运行以下语句其中之一初始化项目
用npx的话 (也是官方推荐的做法)
npx create-react-app demo
用npm
npm init react-app my-app
用yarn
yarn create react-app my-app
然后你大概得到了以下的项目结构
demo
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
稍微修改下项目目录,把src下面所有文件都删掉了,只留下index.js ,编辑index.js
import React from 'react'
import ReactDOM from 'react-dom'

const App = function (){
  const [title,setTitle] = React.useState('react-redux')
  return (
    <div onClick={()=>{setTitle('react-hooks')}}>{title}</div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
命令行 npm start 或者 yarn start 至此~我们的项目初始化结束

引入hooks

在src下面新建文件 store.js
首先用react提供的createContext 创建一个Context
export const GlobalContext = React.createContext({})

然后构造一个最外层的GlobalProvider组件用来包裹子组件
用useState函数定义了store里面的appName字段以及修改该字段的方法,
并在value里面传递给后面的子组件

完整的store.js在下面 其实这一步就对应了redux中的createStore和reducer
import React from 'react'

export const GlobalContext = React.createContext({})

export function GlobalProvider(props) {
  const [appName, setAppName] = React.useState('react-redux')
  return (
    <GlobalContext.Provider
      value={{
        appName,
        setAppName
      }}
    >
      {props.children}
    </GlobalContext.Provider>
  )
}

修改index.js 用store.js里面提供的<GlobalProvider>组件包裹<App>组件
至此 改造已经完成
!!!惊不惊喜 意不意外 没有react-redux 的connect 函数 没有action 没有dispatch
没有reducer ~~~
import React from 'react'
import ReactDOM from 'react-dom'
import { GlobalProvider, GlobalContext } from './store'

const App = function (){
  const [title,setTitle] = React.useState('react-redux')
  return (
    <div onClick={()=>{setTitle('react-hooks')}}>{title}</div>
  )
}

ReactDOM.render(
  <GlobalProvider>
    <App />
  </GlobalProvider>
  , document.getElementById('root'))

实验

在src 下面新建components文件夹 新建两个文件作为验证

├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── components ├──button.js
    |              ├──show.js
    |
    ├── index.js
    ├── store.js
    

button.js 调用store.setAppName方法
import React from 'react'
import { GlobalContext } from '../store'

export default function ButtonComponent() {
  const store = React.useContext(GlobalContext)
  return (
    <div>
      这个是button组件,点击按钮将react-redux 变成react-hooks
      <button onClick={()=>{store.setAppName('react-hooks')}}>切换</button>
    </div>
  )
}
show.js 用来显示appName
import React from 'react'
import { GlobalContext } from '../store'

export default function ShowComponent() {
  const store = React.useContext(GlobalContext)
  return (
    <div>
      <h1>{store.appName}</h1>
    </div>
  )
}
再将这两个组件整合到index.js中去
import React from 'react'
import ReactDOM from 'react-dom'
import { GlobalProvider, GlobalContext } from './store'


import ButtonComponent from './components/button'
import ShowComponent from './components/show'

const App = function (){
  const [title,setTitle] = React.useState('react-redux')
  return (
    <div onClick={()=>{setTitle('react-hooks')}}>
      <ButtonComponent />
      <ShowComponent />
    </div>
  )
}

ReactDOM.render(
  <GlobalProvider>
    <App />
  </GlobalProvider>
  , document.getElementById('root'))


npm start 看到效果
至此 构建工作结束
感言: hooks 处理数据较redux 更清晰,不需要绕来绕去
如果更偏爱redux的处理方式 react 也提供了reducer 

该项目地址 https://github.com/Tangpriest/hooks_demo