本篇文章的受众为使用过redux,并且决定替换掉redux的人群,小白劝退哦
一.useContext使用
1.用途:传值,从父到子,孙,孙孙.. 都可以拿到值
2.用法:
- 在外面先定义Context
import { createContext } from 'react';
const Context = createContext(null);
export default Context;
- 在最外层套上<Context.Provider>,这样全局都可以拿到值
/**
* app容器
*/
import React, { useReducer } from 'react';
import './app.css';
import reducer from './reducers';
import Context from './context';
import TodoList from './components/todoList'
import AddTodo from './components/AddTodo';
import Filter from './components/Filter';
function App() {
const [state, dispatch] = useReducer(reducer, {
filter: 'SHOW_ALL',
todoList: [],
});
return (
//在最外层嵌套
<Context.Provider value={{ state, dispatch }}>
<div>做程序员真难</div>
<TodoList />
<AddTodo />
<Filter />
</Context.Provider>
);
}
export default App;
-
子组件就可以拿到值
import React, { useContext, useEffect } from 'react'; import Context from '../../context'; //必须是子组件 const TodoList = () => { //state, dispatch就是value里写的,传过来的值 const { state, dispatch } = useContext(Context); }; export default TodoList;
我们看到,通过这种方式,实现了传值问题,只要<Context.Provider>套在最外层,其实在全局都可以拿到值。 我们知道redux是一个全局的状态管理,相当于一个前端的数据存储库,这就肯定包括取值和往里面存值,我们现在通过useContext已经实现了全局取值了,那怎么实现把值放进去呢? 这也是我之前困惑的地方,现在知道了,通过useReducer的dispatch,熟悉redux的小伙伴对于dispatch肯定很熟悉,没错,和redux的dispatch的作用一样。
二.useReducer使用
useState的替代方案,它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch方法。
1.用途:通过dispatch,改变值
2.与useState的关系
const [count, setCount] = useState(initialCount);
这是一个useState,count
的初始值是initialCount
,我们想要改变count
的值,只能使用setCount
;
现在假设有10个useState
,我们应该怎样去简化代码?答案就是使用useReducer.
3.用法:
const [state, dispatch] = useReducer(reducer, initialArg, init);
reducer
:是一个方法((state, action) => newState
),它接受两个参数,state, action
,返回一个新的newState
action
:就是dispatch里面的内容
新的newState
:就是initialArg
初始值这样格式的state,也就是你经过dispatch数据更新之后返回的新的初始值格式的值。举例说明:
/**
* app容器
*/
import React, { useReducer } from 'react';
import './app.css';
import reducer from './reducers';
import Context from './context';
import TodoList from './components/todoList'
import AddTodo from './components/AddTodo';
import Filter from './components/Filter';
function App() {
const [state, dispatch] = useReducer(reducer, {
filter: 'SHOW_ALL',
todoList: [],
});
return (
<Context.Provider value={{ state, dispatch }}>
<div>做程序员真难</div>
<TodoList />
<AddTodo />
<Filter />
</Context.Provider>
);
}
export default App;
上面的reducer是这样的
function filterFun(state, action) {
switch (action.type) {
case 'SET_FILTER':
return action.filter;
default:
return state;
}
}
const todoListFun = (state, action) => {
switch (action.type) {
case 'INIT_TODOS':
return action.todoList;
case 'TOGGLE_TODO':
return state.map((todo, index) => {
if (index === action.index) return { ...todo, isComplete: !todo.isComplete };
return todo;
});
case 'ADD_TODO':
return [...state, { text: action.text, isComplete: false }];
default:
return state;
}
};
function reducer(state, action) {
//返回值的格式与初始值保持一致
//action:{
// type: 'INIT_TODOS',
// todoList,
// }
return {
filter: filterFun(state.filter, action),
todoList: todoListFun(state.todoList, action),
};
}
export default reducer;
怎样触发dispatch?
dispatch({
type: 'INIT_TODOS',
todoList,
});
todoList是在业务逻辑中,我们需要获得的值(例如后端拿到的值),我们想把这个值放在中心处理中,就要dispatch进去,我们通过上面的方式,跟redux一致,不做过多解释。
dispatch执行之后,就会自动触发reducer,dispatch里面对象,会通过action,传到这里,之 后返回一个对应的值,并且会自动渲染,这和redux机制保持一致。
通过这种方式,就实现了简易的替代redux的使用。
function reducer(state, action) {
//action:{
// type: 'INIT_TODOS',
// todoList,
// }
return {
filter: filterFun(state.filter, action),
todoList: todoListFun(state.todoList, action),
};
}
三.useContext和useReducer结合使用代替redux
useContext传值,useReducer设置值,这样就实现了代替redux
附上源码: