Javascript React useReducer:如何组合多个减速器?
我不是Javascript专家,所以我想知道是否有人有一种“优雅”的方法来组合多个简化程序来创建全局状态(比如Redux)。在状态更新多个组件等时不影响性能的功能 假设我有一个store.jsJavascript React useReducer:如何组合多个减速器?,javascript,reactjs,react-redux,react-hooks,reducers,Javascript,Reactjs,React Redux,React Hooks,Reducers,我不是Javascript专家,所以我想知道是否有人有一种“优雅”的方法来组合多个简化程序来创建全局状态(比如Redux)。在状态更新多个组件等时不影响性能的功能 假设我有一个store.js import React, { createContext, useReducer } from "react"; import Rootreducer from "./Rootreducer" export const StoreContext = createContext(); const in
import React, { createContext, useReducer } from "react";
import Rootreducer from "./Rootreducer"
export const StoreContext = createContext();
const initialState = {
....
};
export const StoreProvider = props => {
const [state, dispatch] = useReducer(Rootreducer, initialState);
return (
<StoreContext.Provider value={[state, dispatch]}>
{props.children}
<StoreContext.Provider>
);
};
在
rootReducer.js
文件中,您可以使用redux
中的combinereducer
组合多个reducer。传统的方式是:
import { combineReducers } from 'redux';
const rootReducer = combineReducers({ name: nameReducer});
export default rootReducer;
创建存储时,您可以导入rootReducer
:
import { combineReducers } from 'redux';
let store = createStore(rootReducer);
使用useReducer
hook时,可以将rootReducer
传递给它:
const [state, dispatch] = useReducer(rootReducer, initialState);
希望这对您有用。如果您只是想在没有任何第三方库的情况下实现联合收割机减速器功能,请按以下操作。(参考:Redux源代码) 工作代码在这里 我创建了两个减速器,一个日期减速器和另一个计数器减速器。我把它当作 const[state,dispatch]=useReducer(组合减速机)({ 计数器:计数器减速机, 日期:dateReducer }),初始状态) 组合减速机代码
function combineReducers(reducers) {
return (state = {}, action) => {
const newState = {};
for (let key in reducers) {
newState[key] = reducers[key](state[key], action);
}
return newState;
}
}
用法:提取相应的状态
const { counter, date } = state;
注意:如果愿意,您可以添加更多类似redux的功能
完整的工作代码(如果codepen关闭:)
const{useReducer,useffect}=React;
函数dateReducer(状态、操作){
开关(动作类型){
案例“设置日期”:
返回动作。有效载荷;
打破
违约:
返回状态;
}
}
功能减速机(状态、动作){
console.log('cr:',state);
开关(动作类型){
案例“增量”:{
返回状态+1;
}
“减量”一案:{
返回状态-1;
}
违约:
返回状态;
}
}
函数组合减速机(减速机){
返回(状态={},操作=>{
const newState={};
用于(输入减速器){
newState[key]=还原器[key](状态[key],操作);
}
返回新闻状态;
}
}
常量初始状态={
柜台:0,,
日期:新日期
};
函数App(){
const[state,dispatch]=useReducer(组合减速机)({
计数器:计数器减速机,
日期:dateReducer
}),初始状态);
console.log(“state”,state);
const{counter,date}=状态;
返回(
异径管
分派({type:'increment'})}>+
{counter.toString()}
分派({type:'decrement'})}>-
日期减速机
{date.toString()}
分派({type:'set_date',payload:new date})}>
设定日期
);
}
const rootElement=document.querySelector(“#root”);
render(,rootElement);
注意:这是一个快速技巧(仅用于学习和演示)联合切片减速机()
最常见的方法是让每个减速器管理自己的状态属性(“切片”):
const combineReducers = (slices) => (state, action) =>
Object.keys(slices).reduce( // use for..in loop, if you prefer it
(acc, prop) => ({
...acc,
[prop]: slices[prop](acc[prop], action),
}),
state
);
例子:
例子:
组合多个useReducer
hook
您还可以组合来自多个useReducer
s的分派和/或状态,如:
const combineDispatch = (...dispatches) => (action) =>
dispatches.forEach((dispatch) => dispatch(action));
例子:
我玩了一会儿,在思考这个问题,因为我也必须处理它 这可能不是最好的方法,但我只是将我的reducer定义为具有键:reducer函数的对象组合:
const counterRed = {
increment: (oldState, action) => ({
...oldState,
counter: oldState.counter + 1
}),
decrement: (oldState, action) => ({
...oldState,
counter: oldState.counter - 1
})
};
及
我把它们组合成这样:
const reducer = (oldState, action) => {
const combinedReducers = { ...dateRed, ...counterRed };
let newState = null;
if (combinedReducers[action.type]) {
newState = combinedReducers[action.type](oldState, action);
}
if (newState) {
return { ...newState };
}
return oldState;
};
这里可以看到一个工作示例:有一个名为的库,专门用于将reducer与上下文api相结合。下面是代码示例
import { useReducer } from 'react';
import combineReducers from 'react-combine-reducers';
const initialIdentity = {
name: 'Harry'
}
const initialLocation = {
country: 'UK',
city: 'London'
}
const identityReducer = (state, action) => {
switch (action.type) {
case 'ACTION_A':
return { ...state, name: 'Puli' };
default: return state;
}
}
const locationReducer = (state, action) => {
switch (action.type) {
case 'ACTION_B':
return { ...state, city: 'Manchester' };
default: return state;
}
}
const [profileReducer, initialProfile] = combineReducers({
identity: [identityReducer, initialIdentity],
location: [locationReducer, initialLocation]
});
const [state, dispatch] = useReducer(profileReducer, initialProfile);
console.log(state);
// Outputs the following state:
// {
// identity: {
// name: "Harry"
// },
// location: {
// country: "UK",
// city: "London"
// }
// }
不要使用useReducer,而是使用useCombineReducers()。可以根据您的要求更改此功能以接受多个参数
const inti ={ count:0, alpha:''}
export function reducer1(state, action) {
switch (action.type)
{
case 'increment':
return {...state , count: state.count + 1};
case 'decrement':
return {...state , count: state.count - 1};
default:
return {count:0};
} }
函数应用程序(){
const[state,dispatch]=使用组合减速机(减速机1、减速机2、inti);
返回(
); }
const Counter=(道具)=>{
返回(
计数:{props.state.Count}
props.dispatch({type:'increment'})}>+
props.dispatch({type:'decrement'})}>-
)}导出默认计数器
const Alpha=(道具)=>{
返回(
Alpha:{props.state.Alpha}
props.dispatch({type:'add',payload:'+'})}>+
props.dispatch({type:'rem',payload:'-'})}>-
)}导出默认Alpha
您是否看到了前面的这个线程,它可能会有帮助,这与他们现在所做的有什么不同?引入挂钩是为了使react应用程序更加优化。正如官方文档中所说:useReducer允许您优化触发深度更新的组件的性能,因为您可以传递分派而不是回调。OP已经在使用useReducer
。我在问你的代码与OP已有的代码有何不同。他问了一个更好的方法。我向他展示了处理场景的两种方法。@MuhammadZeeshan我必须使用redux createStore吗?理想情况下,我想继续使用ContextCompose。有没有可能将这个合并还原函数转换成一个typescript函数?这个函数对我很有用。基于减速器的减速器未正确更新状态。
const combineDispatch = (...dispatches) => (action) =>
dispatches.forEach((dispatch) => dispatch(action));
const [s1, d1] = useReducer(a, {}); // some init state {}
const [s2, d2] = useReducer(b, {}); // some init state {}
// don't forget to memoize again
const combinedDispatch = React.useCallback(combineDispatch(d1, d2), [d1, d2]);
const combinedState = React.useMemo(() => ({ s1, s2, }), [s1, s2]);
// This example uses separate dispatch and state contexts for better render performance
<DispatchContext.Provider value={combinedDispatch}>
<StateContext.Provider value={combinedState}> {children} </StateContext.Provider>
</DispatchContext.Provider>;
const counterRed = {
increment: (oldState, action) => ({
...oldState,
counter: oldState.counter + 1
}),
decrement: (oldState, action) => ({
...oldState,
counter: oldState.counter - 1
})
};
const dateRed = {
set_date: (oldState, action) => ({ ...oldState, date: action.payload })
};
const reducer = (oldState, action) => {
const combinedReducers = { ...dateRed, ...counterRed };
let newState = null;
if (combinedReducers[action.type]) {
newState = combinedReducers[action.type](oldState, action);
}
if (newState) {
return { ...newState };
}
return oldState;
};
import { useReducer } from 'react';
import combineReducers from 'react-combine-reducers';
const initialIdentity = {
name: 'Harry'
}
const initialLocation = {
country: 'UK',
city: 'London'
}
const identityReducer = (state, action) => {
switch (action.type) {
case 'ACTION_A':
return { ...state, name: 'Puli' };
default: return state;
}
}
const locationReducer = (state, action) => {
switch (action.type) {
case 'ACTION_B':
return { ...state, city: 'Manchester' };
default: return state;
}
}
const [profileReducer, initialProfile] = combineReducers({
identity: [identityReducer, initialIdentity],
location: [locationReducer, initialLocation]
});
const [state, dispatch] = useReducer(profileReducer, initialProfile);
console.log(state);
// Outputs the following state:
// {
// identity: {
// name: "Harry"
// },
// location: {
// country: "UK",
// city: "London"
// }
// }
const inti ={ count:0, alpha:''}
export function reducer1(state, action) {
switch (action.type)
{
case 'increment':
return {...state , count: state.count + 1};
case 'decrement':
return {...state , count: state.count - 1};
default:
return {count:0};
} }
export function reducer2(state, action) {
switch (action.type) {
case 'add':
return {...state , alpha: state.alpha + action.payload };
case 'rem':
return {...state , alpha: state.alpha + action.payload};
default:
return {alpha:''};
}}
function useCombineReducers(reducer1,reducer2, init) {
const [state,setState] = useState(init);
function dispatch(action)
{
let ns = null;
if(action.type == 'add' || action.type=="rem")
{
ns = reducer2(state,action)
}
else
{
ns = reducer1(state,action)
}
setState(ns);
}
return [state, dispatch];}
function App() {
const [state,dispatch] = useCombineReducers(reducer1,reducer2,inti);
return (
<>
<Provider >
<Counter state ={state} dispatch={dispatch}></Counter>
<Alpha state ={state} dispatch={dispatch}></Alpha>
</Provider>
</>
); }
const Counter = (props) => {
return (
<div style ={{Border:'10px', width:'20px'}}>
Count : {props.state.count}
<button onClick={()=> props.dispatch({type: 'increment'})}> + </button>
<button onClick={()=> props.dispatch({type: 'decrement'})}> - </button>
</div>
)} export default Counter
const Alpha = (props) => {
return (
<div style ={{Border:'10px', width:'20px'}}>
Alpha : {props.state.alpha}
<button onClick={()=> props.dispatch({type: 'add',payload:'+'})}> + </button>
<button onClick={()=> props.dispatch({type: 'rem',payload:'-'})}> - </button>
</div>
)} export default Alpha