useReducer
useReducer是useState的复杂版,用来践行Flux/Redux的思想
创建代码步骤如下:
- 1、创建初始化值initialState
- 2、创建所有操作reducer(state,action)
- 3、传给useReducer,得到读和写API
- 4、调用
写{{type:'操作类型'}}
我们来看一下具体代码
import React from 'react'
const initial = {
n:0
}
const reducer = (state,action)=>{
if(action.type === 'add'){
return {n:state.n+action.number}
}else if(action.type === 'multi'){
return {n:state.n*2}
}else{
throw new Error('unkown type')
}
}
export default function App(){
const [state,dispatch] = React.useReducer(reducer,initial)
const {n} = state
const onClick = () => {
dispatch({type:'add',number: 1})
}
const onClick2 = () =>{
dispatch({type:'add',number: 2})
}
return <div className="App">
<h1>n:{n}</h1>
<button onClick={onClick}>+1</button>
<button onClick={onClick2}>+2</button>
</div>
}
复制代码
渲染结果为: 可以进行对n进行+1和+2操作
如何代替Redux
步骤如下:
- 1、将数据集中在一个store对象
- 2、将所有操作集中在reducer*
- 3、创建一个Context
- 4、创建对数据的读写API
- 5、将第四步的内容放到第三步的Context
- 6、用Context.Provider将Context提供给所有组件
- 7、各个组件用useContext获取读写API
我们通过例子来说明,
const store = {
user: null,
books: null,
movies: null
};
function reducer(state, action) {
switch (action.type) {
case "setUser":
return { ...state, user: action.user };
case "setBooks":
return { ...state, books: action.books };
case "setMovies":
return { ...state, movies: action.movies };
default:
throw new Error();
}
}
const Context = React.createContext(null);
export default function App() {
const [state, dispatch] = useReducer(reducer, store);
const api = { state, dispatch };
return (
<Context.Provider value={api}>
<User />
<hr />
<Books />
<Movies />
</Context.Provider>
);
}
function User() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/user").then(user => {
dispatch({ type: "setUser", user: user });
});
}, []);
return (
<div>
<h1>个人信息</h1>
<div>name: {state.user ? state.user.name : ""}</div>
</div>
);
}
function Books() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/books").then(books => {
dispatch({ type: "setBooks", books: books });
});
}, []);
return (
<div>
<h1>我的书籍</h1>
<ol>
{state.books ? state.books.map(book => <li key={book.id}>{book.name}</li>) : "加载中"}
</ol>
</div>
);
}
function Movies() {
const { state, dispatch } = useContext(Context);
useEffect(() => {
ajax("/movies").then(movies => {
dispatch({ type: "setMovies", movies: movies });
});
}, []);
return (
<div>
<h1>我的电影</h1>
<ol>
{state.movies
? state.movies.map(movie => <li key={movie.id}>{movie.name}</li>)
: "加载中"}
</ol>
</div>
);
}
// 帮助函数
// 假 ajax
// 两秒钟后,根据 path 返回一个对象,必定成功不会失败
function ajax(path) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (path === "/user") {
resolve({
id: 1,
name: ""
});
} else if (path === "/books") {
resolve([
{
id: 1,
name: "JavaScript 高级程序设计"
},
{
id: 2,
name: "JavaScript 精粹"
}
]);
} else if (path === "/movies") {
resolve([
{
id: 1,
name: "爱在黎明破晓前"
},
{
id: 2,
name: "恋恋笔记本"
}
]);
}
}, 2000);
});
}
复制代码
数据在两秒后加载出来:
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END