useContext与useReducer结合使用达到react-redux的效果
userContext
传统的context使用是一件比较麻烦的事情,而且代码可读性比较差。使用useContext只需要一下几个步骤
- 使用React.createContext创建context对象
- 创建顶层容器组件
- 将state、setState传递给子组件
- 子组件使用useContext获取state、setState,达到获取值修改值的目的
import React, {useState, useContext} from 'react'
// 1.创建context对象
const Context = React.createContext()
// 2. 顶层容器组件创建
export function ContentHook(props) {
// 3.各种state、setState
const [name, setName] = useState('jgmiu')
const [age, setAge] = useState('24')
// 通过Context.Provider将值与改变值的方法传递下去
return (
<Context.Provider value = {{name, setName, age, setAge}}>
<h3>useContent</h3>
<Child1 />
<Child2 />
</Context.Provider>
)
}
function Child1(props) {
// 得到context对象 获取里面的值用于展示
const user = useContext(Context)
return(
<div className={'c1'}>
<h3>子组件1</h3>
<span>name:{user.name} age:{user.age} </span>
</div>
)
}
function Child2(props) {
const user = useContext(Context)
// 得到set方法
const handleName = e =>{
user.setName('缪佳耕')
}
const handleAge = e => {
user.setAge(30)
}
return(
<div className={'c2'}>
<h3>子组件2</h3>
<button onClick={handleName}>name</button>
<button onClick={handleAge}>age</button>
</div>
)
}
子组件2改变context对象里面的值,子组件1也会跟着变
userReducer
userReducer接受两个参数,第一个参数是reducer,第二个参数是store,返回state与dispatch
// 1. store 初始值
const store = {
user: {name: 'jgmiu', age: 24},
}
// 2. reducer
const user = (state, action) => {
switch (action.type) {
case 'name':
return {...state, name: action.value}
case 'age':
return {...state, age: action.value}
default:
return state
}
}
// 使用useReducer得到 state 与dispatch
const [state, dispatch] = useReducer(user, store)
在实际开发中,可能有很多歌reducer。在以前使用react-redux的使用提供一个方法combineReducers,用于合并多个reducer。经过测试这里使用这个方法会报错所以需要自己去封装一个
// 自定义合并reducer函数
const combineReducers = (reducers) => {
return function(state, action) {
return Object.keys(reducers)
.map(k => ({[k]: reducers[k](state[k], action)}))
.reduce((prev, cur) =>(Object.assign({}, prev, cur)))
}
}
两者结合
两者结合使用能够达到react-redux的效果。其主要思路如下:
- 使用userReducer得到state与dispatch
- 使用userContext将state与dispatch共享到子组件
import React, { useReducer,useContext } from 'react'
// 创建store
const store = {
user: {name: 'jgmiu', age: 24},
params: {key: 'key', date: '20190802'}
}
// reducer 创建
const user = (state, action) => {
switch (action.type) {
case 'name':
return {...state, name: action.value}
case 'age':
return {...state, age: action.value}
default:
return state
}
}
const params = (state, action) => {
switch (action.type) {
case 'key':
return {...state, key: action.value}
case 'date':
return {...state, date: action.value}
default:
return state
}
}
// 自定义合并reducer函数
const combineReducers = (reducers) => {
return function(state, action) {
return Object.keys(reducers)
.map(k => ({[k]: reducers[k](state[k], action)}))
.reduce((prev, cur) =>(Object.assign({}, prev, cur)))
}
}
const reducers = combineReducers({user, params})
// 创建Context放在最上层父组件
const Context = React.createContext()
export default function Redux2(props) {
// 在最顶层得到 store 与 dispatch
const [state, dispatch] = useReducer(reducers, store)
return (
<Context.Provider value = {{state, dispatch}}>
<h1>使用useContext/useReducer代替reducer</h1>
<Child1 />
<Child2 />
</Context.Provider>
)
}
// 子组件1
function Child1(props) {
const context = useContext(Context)
const user = context.state.user
const params = context.state.params
return(
<div className={'c1'}>
<h3>子组件1</h3>
<p><span>name: {user.name} age: {user.age}</span></p>
<p><span>key: {params.key} date: {params.date}</span></p>
</div>
)
}
// 子组件2
function Child2(props) {
const context = useContext(Context)
const handleName = e =>{
context.dispatch({type: 'name', value: 'miujg'})
}
const handleAge = e => {
context.dispatch({type: 'age', value: 30})
}
const handleKey = e => {
context.dispatch({type: 'key', value: 'keykeykey'})
}
const handleDate = e=> {
context.dispatch({type: 'date', value: '1212121212'})
}
return(
<div className={'c2'}>
<h3>子组件2</h3>
<button onClick={handleName}>name</button>
<button onClick={handleAge}>age</button>
<button onClick={handleKey}>key</button>
<button onClick={handleDate}>date</button>
</div>
)
}
简单demo的完整代码
小结
网上也有很多例子,很多标题都是说使用hook来代替传统的redux。能不能代替?小项目能代替?大项目也能代替?这些问题还得多实践才知道~~~~~