如何通过useReducer和createContext实现Redux原理的替代方案示例解析?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1519个文字,预计阅读时间需要7分钟。
目录前言采用react-redux实现采用react hooks模拟redux实现异步action总结前言最近看到很多人使用`useReducer`+`createContext`实现一个简易的Redux,今天我也试了一下,下面是我的实践总结。
采用react-redux实现首先,使用`react-redux`来实现Redux状态管理,这是一个非常成熟和方便的方法。下面是一个简单的例子:
javascriptimport React from 'react';import { createStore } from 'redux';import { Provider, connect } from 'react-redux';
// Action Typesconst ADD_COUNT='ADD_COUNT';const MINUS_COUNT='MINUS_COUNT';
// Reducerconst countReducer=(state={ count: 0 }, action)=> { switch (action.type) { case ADD_COUNT: return { ...state, count: state.count + 1 }; case MINUS_COUNT: return { ...state, count: state.count - 1 }; default: return state; }};
// Action Creatorsconst addCount=()=> ({ type: ADD_COUNT });const minusCount=()=> ({ type: MINUS_COUNT });
// Componentsconst Counter=({ count, addCount, minusCount })=> ( Count: {count} );
const mapStateToProps=state=> ({ count: state.count });
const mapDispatchToProps={ addCount, minusCount };
const App=connect(mapStateToProps, mapDispatchToProps)(Counter);
// Storeconst store=createStore(countReducer);
// Appconst AppWithRedux=()=> ( );
export default AppWithRedux;
采用react hooks模拟redux实现接下来,使用`react hooks`来模拟Redux实现,这是一种不依赖第三方库的方法。下面是一个简单的例子:
javascriptimport React, { useState, useReducer, useContext } from 'react';
// Action Typesconst ADD_COUNT='ADD_COUNT';const MINUS_COUNT='MINUS_COUNT';
// Reducerconst countReducer=(state, action)=> { switch (action.type) { case ADD_COUNT: return { ...state, count: state.count + 1 }; case MINUS_COUNT: return { ...state, count: state.count - 1 }; default: return state; }};
// Contextconst CountContext=React.createContext();
// Providerconst CountProvider=({ children })=> { const [state, dispatch]=useReducer(countReducer, { count: 0 }); return ( {children} );};
// Componentsconst Counter=()=> { const { state, dispatch }=useContext(CountContext); return ( Count: {state.count} );};
// Appconst App=()=> ( );
export default App;
异步action在Redux中,异步action是非常常见的需求。以下是一个使用`redux-thunk`中间件实现异步action的例子:
javascriptimport React from 'react';import { createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk';
// Action Typesconst FETCH_DATA='FETCH_DATA';
// Reducerconst dataReducer=(state={ data: null }, action)=> { switch (action.type) { case FETCH_DATA: return { ...state, data: action.payload }; default: return state; }};
// Async Action Creatorconst fetchData=()=> async dispatch=> { const response=await fetch('https://api.example.com/data'); const data=await response.json(); dispatch({ type: FETCH_DATA, payload: data });};
// Storeconst store=createStore(dataReducer, applyMiddleware(thunk));
// Appconst App=()=> ( Data: {store.getState().data} );
export default App;
总结以上就是我对使用`useReducer`+`createContext`实现简易Redux的一些实践和总结。虽然这个方法相对简单,但它可以帮助我们更好地理解Redux的核心概念和原理。
目录
- 前言
- 采用react-redux实现
- 采用react hooks模拟redux实现
- 异步action
- 总结
前言
最近看到很多采用useReducer + createContext 实现一个简易的redux的方案,今天亲自试了一下,发现还是会有一些区别的。
采用react-redux实现
这里使用react-redux 实现一个简单的状态管理例子。
App.jsx根组件
import React from 'react'; import { Button } from './Button'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import A from './a'; export default function ButtonDemo1() { const reducer = (state, action) => { const { name, theme } = state; switch (action.type) { case 'UPDATENAME': return { ...state, name: `${name} + 1`, }; case 'UPDATETHEME': return { ...state, theme: theme === 'dark' ? 'light' : 'dark', }; default: return state; } }; const store = createStore(reducer, { name: 'fx', theme: 'dark', }); return ( <Provider store={store}> <div> <Button /> <A /> </div> </Provider> ); }
A组件用于dispatch和接收store。
A.jsx
import React, { useContext } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { reduxContent } from './index1'; export default function A() { const dispatch = useDispatch(); return ( <div onClick={() => dispatch({ type: 'UPDATENAME' })}> {useSelector((state) => state.name)} </div> ); }
效果如图:
可以看到,Button组件未使用redux store,因此正常渲染了一次。
采用react hooks模拟redux实现
这里采用useReducer + createContext 模拟实现一个redux:
App.jsx
import React, { useReducer, createContext } from 'react'; import { Button } from 'concis'; import A from './a'; export const reduxContent = createContext({}); export default function ButtonDemo1() { const reducer = (state, action) => { const { name, theme } = state; switch (action.type) { case 'UPDATENAME': return { ...state, name: `${name} + 1`, }; case 'UPDATETHEME': return { ...state, theme: theme === 'dark' ? 'light' : 'dark', }; default: return state; } }; const [redux, dispatch] = useReducer(reducer, { name: 'fx', theme: 'dark', }); return ( <reduxContent.Provider value={{ redux, dispatch }}> <Button /> <A /> </reduxContent.Provider> ); }
A.jsx
import React, { useContext } from 'react'; import { reduxContent } from './index1'; export default function A() { const { redux, dispatch } = useContext(reduxContent); return ( <div onClick={() => dispatch({ type: 'UPDATENAME' })}> {redux.name} </div> ); }
同样,子组件也可以对store中的状态进行get和dispatch,但是会出现这样的问题:
可以看到,Button组件并没有使用store中的内容,但是会随着A组件一起跟着重新渲染,原因其实就是采用这种方式store是存储在根组件的,根组件状态发生了变化(useReducer),子组件跟着一起重新渲染了,因此解决这个问题的思路其实和解决常规的子组件没变化一起被更新的思路是一样的。
可以采用 useMemo限制 + memo 浅比较。
因此只需要在App.jsx中这样修改:
const renderButton = React.useMemo(() => { return <Button />; }, []); return ( <reduxContent.Provider value={{ redux, dispatch }}> <div style={{ display: 'flex', flexWrap: 'wrap' }}> {renderButton} <A /> </div> </reduxContent.Provider> ); }
Button.jsx
const Button = (props) => { ...... }) export default React.memo(Button);
异步action
同样,如果需要异步dispatch的话,简单的场景其实单纯使用异步操作就可以完成,但是在复杂的场景下很难对于异步流进行管理和维护,这时就需要借助redux中间件了,类似redux-thunk、redux-saga,而这也是使用hooks无法实现的,无法处理副作用,拦截action去更好的reducer。
总结
当然,并不是说采用react hooks所实现的状态管理方式没有好处,这样可以更加贴合react原生,采用react自身所提供的hook,并且可以减少项目中的redux各种实例、减少代码体积,对于小型项目或是不需要很多全局状态的项目,这种方式确实是不错的选择。但是redux仍然是大型项目中最可靠的保障存在。
以上就是useReducer createContext代替Redux原理示例解析的详细内容,更多关于useReducer createContext代替Redux的资料请关注自由互联其它相关文章!
本文共计1519个文字,预计阅读时间需要7分钟。
目录前言采用react-redux实现采用react hooks模拟redux实现异步action总结前言最近看到很多人使用`useReducer`+`createContext`实现一个简易的Redux,今天我也试了一下,下面是我的实践总结。
采用react-redux实现首先,使用`react-redux`来实现Redux状态管理,这是一个非常成熟和方便的方法。下面是一个简单的例子:
javascriptimport React from 'react';import { createStore } from 'redux';import { Provider, connect } from 'react-redux';
// Action Typesconst ADD_COUNT='ADD_COUNT';const MINUS_COUNT='MINUS_COUNT';
// Reducerconst countReducer=(state={ count: 0 }, action)=> { switch (action.type) { case ADD_COUNT: return { ...state, count: state.count + 1 }; case MINUS_COUNT: return { ...state, count: state.count - 1 }; default: return state; }};
// Action Creatorsconst addCount=()=> ({ type: ADD_COUNT });const minusCount=()=> ({ type: MINUS_COUNT });
// Componentsconst Counter=({ count, addCount, minusCount })=> ( Count: {count} );
const mapStateToProps=state=> ({ count: state.count });
const mapDispatchToProps={ addCount, minusCount };
const App=connect(mapStateToProps, mapDispatchToProps)(Counter);
// Storeconst store=createStore(countReducer);
// Appconst AppWithRedux=()=> ( );
export default AppWithRedux;
采用react hooks模拟redux实现接下来,使用`react hooks`来模拟Redux实现,这是一种不依赖第三方库的方法。下面是一个简单的例子:
javascriptimport React, { useState, useReducer, useContext } from 'react';
// Action Typesconst ADD_COUNT='ADD_COUNT';const MINUS_COUNT='MINUS_COUNT';
// Reducerconst countReducer=(state, action)=> { switch (action.type) { case ADD_COUNT: return { ...state, count: state.count + 1 }; case MINUS_COUNT: return { ...state, count: state.count - 1 }; default: return state; }};
// Contextconst CountContext=React.createContext();
// Providerconst CountProvider=({ children })=> { const [state, dispatch]=useReducer(countReducer, { count: 0 }); return ( {children} );};
// Componentsconst Counter=()=> { const { state, dispatch }=useContext(CountContext); return ( Count: {state.count} );};
// Appconst App=()=> ( );
export default App;
异步action在Redux中,异步action是非常常见的需求。以下是一个使用`redux-thunk`中间件实现异步action的例子:
javascriptimport React from 'react';import { createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk';
// Action Typesconst FETCH_DATA='FETCH_DATA';
// Reducerconst dataReducer=(state={ data: null }, action)=> { switch (action.type) { case FETCH_DATA: return { ...state, data: action.payload }; default: return state; }};
// Async Action Creatorconst fetchData=()=> async dispatch=> { const response=await fetch('https://api.example.com/data'); const data=await response.json(); dispatch({ type: FETCH_DATA, payload: data });};
// Storeconst store=createStore(dataReducer, applyMiddleware(thunk));
// Appconst App=()=> ( Data: {store.getState().data} );
export default App;
总结以上就是我对使用`useReducer`+`createContext`实现简易Redux的一些实践和总结。虽然这个方法相对简单,但它可以帮助我们更好地理解Redux的核心概念和原理。
目录
- 前言
- 采用react-redux实现
- 采用react hooks模拟redux实现
- 异步action
- 总结
前言
最近看到很多采用useReducer + createContext 实现一个简易的redux的方案,今天亲自试了一下,发现还是会有一些区别的。
采用react-redux实现
这里使用react-redux 实现一个简单的状态管理例子。
App.jsx根组件
import React from 'react'; import { Button } from './Button'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import A from './a'; export default function ButtonDemo1() { const reducer = (state, action) => { const { name, theme } = state; switch (action.type) { case 'UPDATENAME': return { ...state, name: `${name} + 1`, }; case 'UPDATETHEME': return { ...state, theme: theme === 'dark' ? 'light' : 'dark', }; default: return state; } }; const store = createStore(reducer, { name: 'fx', theme: 'dark', }); return ( <Provider store={store}> <div> <Button /> <A /> </div> </Provider> ); }
A组件用于dispatch和接收store。
A.jsx
import React, { useContext } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { reduxContent } from './index1'; export default function A() { const dispatch = useDispatch(); return ( <div onClick={() => dispatch({ type: 'UPDATENAME' })}> {useSelector((state) => state.name)} </div> ); }
效果如图:
可以看到,Button组件未使用redux store,因此正常渲染了一次。
采用react hooks模拟redux实现
这里采用useReducer + createContext 模拟实现一个redux:
App.jsx
import React, { useReducer, createContext } from 'react'; import { Button } from 'concis'; import A from './a'; export const reduxContent = createContext({}); export default function ButtonDemo1() { const reducer = (state, action) => { const { name, theme } = state; switch (action.type) { case 'UPDATENAME': return { ...state, name: `${name} + 1`, }; case 'UPDATETHEME': return { ...state, theme: theme === 'dark' ? 'light' : 'dark', }; default: return state; } }; const [redux, dispatch] = useReducer(reducer, { name: 'fx', theme: 'dark', }); return ( <reduxContent.Provider value={{ redux, dispatch }}> <Button /> <A /> </reduxContent.Provider> ); }
A.jsx
import React, { useContext } from 'react'; import { reduxContent } from './index1'; export default function A() { const { redux, dispatch } = useContext(reduxContent); return ( <div onClick={() => dispatch({ type: 'UPDATENAME' })}> {redux.name} </div> ); }
同样,子组件也可以对store中的状态进行get和dispatch,但是会出现这样的问题:
可以看到,Button组件并没有使用store中的内容,但是会随着A组件一起跟着重新渲染,原因其实就是采用这种方式store是存储在根组件的,根组件状态发生了变化(useReducer),子组件跟着一起重新渲染了,因此解决这个问题的思路其实和解决常规的子组件没变化一起被更新的思路是一样的。
可以采用 useMemo限制 + memo 浅比较。
因此只需要在App.jsx中这样修改:
const renderButton = React.useMemo(() => { return <Button />; }, []); return ( <reduxContent.Provider value={{ redux, dispatch }}> <div style={{ display: 'flex', flexWrap: 'wrap' }}> {renderButton} <A /> </div> </reduxContent.Provider> ); }
Button.jsx
const Button = (props) => { ...... }) export default React.memo(Button);
异步action
同样,如果需要异步dispatch的话,简单的场景其实单纯使用异步操作就可以完成,但是在复杂的场景下很难对于异步流进行管理和维护,这时就需要借助redux中间件了,类似redux-thunk、redux-saga,而这也是使用hooks无法实现的,无法处理副作用,拦截action去更好的reducer。
总结
当然,并不是说采用react hooks所实现的状态管理方式没有好处,这样可以更加贴合react原生,采用react自身所提供的hook,并且可以减少项目中的redux各种实例、减少代码体积,对于小型项目或是不需要很多全局状态的项目,这种方式确实是不错的选择。但是redux仍然是大型项目中最可靠的保障存在。
以上就是useReducer createContext代替Redux原理示例解析的详细内容,更多关于useReducer createContext代替Redux的资料请关注自由互联其它相关文章!

