使用useReducer和Context替代redux
步骤:
- 将数据集中在一个store对象
- 将所有操作集中在reducer
- 创建一个Context
- 创建对数据的读写API
- 将第4步的内容放到第3步的Context
- 用Context.Provider将Context提供给所有组件
- 各个组件用useContext获取读写API
代码演示:
import React, { Dispatch, useEffect, useContext, createContext, useReducer } from 'react'
import './App.css'
interface IPersonState {
books: string[]
movies: string[]
}
type IPersonAction = {
type: 'getBooks' | 'getMovies'
payload: string[]
}
const initialState: IPersonState = {
books: [],
movies: [],
}
function reducer(state: IPersonState = initialState, action: IPersonAction) {
if (action.type === 'getBooks') {
return { ...state, books: action.payload }
}
if (action.type === 'getMovies') {
return { ...state, movies: action.payload }
}
return state
}
export interface IContextValue {
state: IPersonState
dispatch: Dispatch<IPersonAction>
}
const Context = createContext<IContextValue | undefined>(undefined)
function Person() {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<Context.Provider value={{ state, dispatch }}>
<div>
<Books />
<Movies />
</div>
</Context.Provider>
)
}
function Books() {
const { state, dispatch } = useContext(Context)!
useEffect(() => {
fetch('http://api.kuanglinfeng.com')
.then((response) => response.json())
.then((data) => dispatch({ type: 'getBooks', payload: data.books }))
}, [])
return (
<div>
<h1>我的书籍</h1>
<ul>
{state.books!.map((book) => (
<li key={book}>{book}</li>
))}
</ul>
</div>
)
}
function Movies() {
const { state, dispatch } = useContext(Context)!
useEffect(() => {
fetch('http://api.kuanglinfeng.com')
.then((response) => response.json())
.then((data) => dispatch({ type: 'getMovies', payload: data.movies }))
}, [])
return (
<div>
<h1>我的电影</h1>
{state.movies.map((movie) => (
<li key={movie}>{movie}</li>
))}
</div>
)
}
function App() {
return (
<div className="App">
<Person />
</div>
)
}
export default App
如何对reducer进行拆分?
答:可将reducer写成多个对象的形式,合并所有的子reducer时只需要{...reducer1, ...reducer2, ...}即可