React系列-状态逻辑复用(下)
2020/5/18 11:27:04
本文主要是介绍React系列-状态逻辑复用(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
React系列-状态逻辑复用(上)
React系列-状态逻辑复用(中)
React系列-状态逻辑复用(下)
我们在第二篇文章中介绍了一些常用的hooks,接着我们继续来介绍剩下的hooks吧
useReducer
作为useState 的替代方案。它接收一个形如
(state, action) => newState 的 reducer
,并返回当前的 state 以及与其配套的 dispatch 方法
。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)
不明白Redux工作流的同学可以看看这篇Redux系列之分析中间件原理(附经验分享)
为什么使用
官方说法: 在某些场景下,useReducer 会比 useState 更适用,
例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等
。并且,使用 useReducer 还能给那些会触发深更新的组件做性能优化
,因为你可以向子组件传递 dispatch 而不是回调函数 。
总结来说:
如果你的state是一个数组或者对象等复杂数据结构
如果你的state变化很复杂,
经常一个操作需要修改很多state
如果你希望构建自动化测试用例来保证程序的稳定性
如果你需要在深层子组件里面去修改一些状态(也就是useReducer+useContext代替Redux)
如果你用应用程序比较大,希望UI和业务能够分开维护
登录场景
举个例子🌰:
登录场景
useState完成登录场景
function LoginPage() { const [name, setName] = useState(''); // 用户名 const [pwd, setPwd] = useState(''); // 密码 const [isLoading, setIsLoading] = useState(false); // 是否展示loading,发送请求中 const [error, setError] = useState(''); // 错误信息 const [isLoggedIn, setIsLoggedIn] = useState(false); // 是否登录 const login = (event) => { event.preventDefault(); setError(''); setIsLoading(true); login({ name, pwd }) .then(() => { setIsLoggedIn(true); setIsLoading(false); }) .catch((error) => { // 登录失败: 显示错误信息、清空输入框用户名、密码、清除loading标识 setError(error.message); setName(''); setPwd(''); setIsLoading(false); }); } return ( // 返回页面JSX Element ) } 复制代码
useReducer完成登录场景
const initState = { name: '', pwd: '', isLoading: false, error: '', isLoggedIn: false, } function loginReducer(state, action) { switch(action.type) { case 'login': return { ...state, isLoading: true, error: '', } case 'success': return { ...state, isLoggedIn: true, isLoading: false, } case 'error': return { ...state, error: action.payload.error, name: '', pwd: '', isLoading: false, } default: return state; } } function LoginPage() { const [state, dispatch] = useReducer(loginReducer, initState); const { name, pwd, isLoading, error, isLoggedIn } = state; const login = (event) => { event.preventDefault(); dispatch({ type: 'login' }); login({ name, pwd }) .then(() => { dispatch({ type: 'success' }); }) .catch((error) => { dispatch({ type: 'error' payload: { error: error.message } }); }); } return ( // 返回页面JSX Element ) } 复制代码
❗️我们的state变化很复杂,经常一个操作需要修改很多state
,另一个好处是所有的state处理都集中到了一起,使得我们对state的变化更有掌控力,同时也更容易复用state逻辑变化代码,比如在其他函数中也需要触发登录success状态,只需要dispatch({ type: 'success' })。
笔者[狗头]认为,暂时应该不会用useReducer
替代useState
,毕竟Redux
的写法实在是很繁琐
复杂数据结构场景
刚好最近笔者的项目就碰到了复杂数据结构场景
,可是并没有用useReducer
来解决,依旧采用useState
,原因很简单:方便
// 定义list类型 export interface IDictList extends IList { extChild: { curPage: number totalSize: number size: number // pageSize list: IList[] } } const [list, setList] = useState<IDictList[]>([]) const change=()=>{ const datalist = JSON.parse(JSON.stringify(list)) // 拷贝对象 地址不同 不过这种写法感觉不好 建议用reducers 应该封装下reducers写法 const data = await getData() const { totalCount, pageSize, list } = data item.extChild.totalSize = totalCount item.extChild.size = pageSize item.extChild.list = list setList(datalist) // 改变 } 复制代码
看typescript写的类型声明就知道了这个list变量是个复杂的数据结构,需要经常需要改变添加extChild.list数组的内容,但是这种Array.prototype.push
,是不会触发更新,做过是通过const datalist = JSON.parse(JSON.stringify(list))
。虽然没有使用useReducer
进行替代,笔者还是推荐大家试试
如何使用
const [state, dispatch] = useReducer(reducer, initialArg, init); 复制代码
知识点合集
引用不变
useReducer返回的state
跟ref一样,引用是不变的,不会随着函数组件的重新更新而变化,因此useReducer也可以解决闭包陷阱
const setCountReducer = (state,action)=>{ switch(action.type){ case 'add': return state+action.value case 'minus': return state-action.value default: return state } } const App = ()=>{ const [count,dispatch] = useReducer(setCountReducer,0) useEffect(()=>{ const timeId = setInterval(()=>{ dispatch({type:'add',value:1}) },1000) return ()=> clearInterval(timeId) },[]) return ( <span>{count}</span> ) } 复制代码
把setCount改成useReducer的dispatch,因为useReducer的dispatch 的身份永远是稳定的 —— 即使 reducer 函数是定义在组件内部并且依赖 props
useContext
为什么使用
如何使用
知识点合集
useLayoutEffect
为什么使用
如何使用
知识点合集
useImperativeHandle
为什么使用
如何使用
知识点合集
自定义hooks
这篇关于React系列-状态逻辑复用(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-24Vue CLI多环境配置学习:从入门到实践
- 2024-11-24Vue CLI多环境配置学习:新手入门教程
- 2024-11-24Vue CLI学习:初学者指南
- 2024-11-24Vue CLI学习:从入门到上手的简单教程
- 2024-11-24Vue3+Vite学习:从零开始的前端开发之旅
- 2024-11-24Vue3阿里系UI组件学习入门教程
- 2024-11-24Vue3的阿里系UI组件学习入门指南
- 2024-11-24Vue3公共组件学习:新手入门教程
- 2024-11-24Vue3公共组件学习入门指南
- 2024-11-24vue3核心功能响应式变量学习