GVKun编程网logo

reactjs – 如何在一个状态内合并多个Reducer?(react setstate 合并)

14

在本文中,我们将给您介绍关于reactjs–如何在一个状态内合并多个Reducer?的详细内容,并且为您解答reactsetstate合并的相关问题,此外,我们还将为您提供关于javascript–R

在本文中,我们将给您介绍关于reactjs – 如何在一个状态内合并多个Reducer?的详细内容,并且为您解答react setstate 合并的相关问题,此外,我们还将为您提供关于javascript – ReactJS:如何在Jest中使用action触发reducer、javascript – 如何使用react-redux中的reducer状态更新值的组件状态?、React useContext & useReducer - 需要应用程序中的全局状态,对使用一个或多个 reducer 感到困惑、React useReducer Hook发射两次/如何将道具传递给reducer?的知识。

本文目录一览:

reactjs – 如何在一个状态内合并多个Reducer?(react setstate 合并)

reactjs – 如何在一个状态内合并多个Reducer?(react setstate 合并)

我正在尝试构建一个应用程序,该应用程序有两个或更多个reducer“回答”我的storeState中的一个对象.

例:

storeState {
    app: {...},comments: [ ...two or more states inside one... ]
}

我已经尝试了以下使用不起作用的combineReducers,我的注释状态变成了一个空对象.

import { combineReducers } from 'redux';
import commentFacebookReducer from './twitch';
import commentYoutubeReducer from './reddit';
import appReducer from './app';

const rootReducer = combineReducers({
  comments: [commentFacebookReducer,commentYoutubeReducer],app: appReducer
});

export default rootReducer;

我已经尝试将我的评论缩减器组合在一起,然后将它们组合在rootReducer中:

import { combineReducers } from 'redux';
import commentFacebookReducer from './twitch';
import commentYoutubeReducer from './reddit';
import appReducer from './app';

const commentReducers = combineReducers({
  commentFacebookReducer,commentYoutubeReducer
});

const rootReducer = combineReducers({
  comments: commentReducers,app: appReducer
});

export default rootReducer;

但它给了我一个像以下那样的storeState.但我需要一个注释数组的状态,我不能处理这些减少名称(如commentFacebookReducer或commentYoutubeReducer),因为我会有数千个这样的减速器.

storeState {
    app: {...},comments: {
        commentFacebookReducer: {...},commentYoutubeReducer: {...}
    }
}
我不认为你可以通过使用combineReducer来做到这一点.因为combineReducer需要一个对象,该对象的每个属性都应该是
一个功能.然后该对象中的每个函数在redux状态树中创建一个单独的属性,该属性的值是该函数返回的值(当调度任何操作时).

此外,您无法在其他reducer中访问一个reducer的状态,因为redux仅将该特定reducer的状态传递给该函数.这意味着你无法在commentYoutubeReducer中获取/更改commentFacebookReducer的状态.

我现在能想到的唯一更好的解决方案是在使用它们时将它们组合在一起(最有可能在mapStatetoProps中).你保持你的减速器就像你这样做:

const commentReducers = combineReducers({
  commentFacebookReducer,app: appReducer
});

现在我们所有的评论都在一个对象中,即(state.comments).现在在mapStatetoProp中你可以做这样的事情,将它们组合在一个对象中::

const mapStatetoProps = state => {
    return {
        comments: Object.keys(state.comments).reduce((d,k) => {return d.concat(a[k])},[] )
    };
};

现在在组件中,您可以使用this.props.comments将它们作为单个数组进行访问

javascript – ReactJS:如何在Jest中使用action触发reducer

javascript – ReactJS:如何在Jest中使用action触发reducer

我正在为减速机测试工作.但是具有动作功能的减速器的返回状态是异常的.

reducer.react-test.js

import reducer from '../../test_module/reducer';

describe('Test Reducer',() => {

  const initStatus = { id: -1,list: [] };

  it('1. has default state',() => {    
    expect(reducer(initStatus,{ type: 'unexpected' })).toEqual({
      ...initStatus
    });    
  });

  it('2. has added once',{ type: "ADD" })).toEqual({
      ...initStatus,id: 0,list: [0],});   
  });

  it('3. has added twice',() => {    
    const afteraddOnce = reducer(initStatus,{ type: "ADD" });
    expect(reducer(afteraddOnce,id: 1,list: [0,1],});    
  });
})

reducer.js

export default function reducer(state={
    id: -1,list: [],},action) {
  switch(action.type) {

    case "ADD": {
      state.id = state.id + 1;
      state.list.push(state.id);
      return {
        ...state,};
    }
  }
  return state;
}

文件夹结构

.
├── __test__
│   └── test_module
│       └── reducer.react-test.js
└── test_module
    └── reducer.js

我的第一和第二个测试用例预计会有效.

但是,当我尝试触发两次动作时,我会从第一个动作存储返回状态.但是返回状态意外地执行了两次ADD操作. (我只期待过一次)

因此,当我开玩笑时,我得到了这个结果:

FAIL  __test__/test_module/reducer.react-test.js
  ● Test Reducer › has added twice

    expect(received).toEqual(expected)

    Expected value to equal:
      {"id": 1,"list": [0,1]}
    Received:
      {"id": 2,1,2]}

    Difference:

    - Expected
    + Received

     Object {
    -  "id": 1,+  "id": 2,"list": Array [
         0,+    2,],}

我必须误解触发减速器功能的用法.我希望得到一些正确的方法来触发减速器的动作并获得预期的结果.

最佳答案
罪魁祸首可以在你的减速器中找到,特别是这些线:

state.id = state.id + 1;
state.list.push(state.id);

这里的reducer既改变状态又返回一个新的状态.改变状态是不好的做法,并可能导致奇怪的效果(就像你正在经历的那样)

所以’2.添加一次’test会将id增加到0.这将在下一次测试期间保留在内存中,其中initialStatus的id为0,而不是-1.在我们的reducer中,state指向initialStatus.所以调用state.id = status.id 1;递增initialStatus的id字段,对于list也是如此.这就是看起来ADD动作被调用三次的原因.

远离减速器中的突变可以帮助解决这个问题.

case "ADD": {
    const newId = state.id + 1;

    return {
      id: newId,list: state.list.concat([newId])
    };
}

记住,永远不要在reducer中改变状态,总是返回新的状态!
(http://redux.js.org/docs/Troubleshooting.html#never-mutate-reducer-arguments)

javascript – 如何使用react-redux中的reducer状态更新值的组件状态?

javascript – 如何使用react-redux中的reducer状态更新值的组件状态?

我有减速器给我carReducer,我可以在EditCar组件中用作道具:

我的carReducer是:

export default function carReducer(state = {},action) {
    switch (action.type) {
        case 'GET_SINGLECAR':
            return {
                ...state,next: action.payload
            }
            break;
    }
    return state;
}

在EditCar组件中,我已将carReducer声明为:

function mapStatetoProps(state) {
        return {
            carReducer: state.carReducer
        }
    }

export default connect(mapStatetoProps,mapdispatchToProps)(EditCar);

现在在同一个组件中,我想在组件加载之前使用此carReducer更新我的intialState cardata.

constructor(props) {
    super(props);
    this.state = {
        cardata: {}
    }
}

我尝试使用componentwillReceiveProps,但是这给了我nextProps.carReducer和this.props.carReducer中的undefined.

componentwillReceiveProps(nextProps) {
    if (nextProps.carReducer != this.props.carReducer) {
        this.setState({ cardata: nextProps.carReducer });
    }
}

我是react-redux的新手,所以任何帮助都非常感谢.谢谢.

解决方法

方法1 – 尝试使用componentDidMount()

componentDidMount() {
  this.setState = ({
    cardata: this.props.carReducer
  })
}

方法2 – 您可以尝试在构造函数本身中执行此操作

constructor(props) {
  super(props);
  this.state = {
    cardata: props.carReducer
  }
}

React useContext & useReducer - 需要应用程序中的全局状态,对使用一个或多个 reducer 感到困惑

React useContext & useReducer - 需要应用程序中的全局状态,对使用一个或多个 reducer 感到困惑

如何解决React useContext & useReducer - 需要应用程序中的全局状态,对使用一个或多个 reducer 感到困惑?

我需要在我的应用中共享信息片段,例如用户详细信息、头像和应用内提醒。我担心我可能没有以正确的方式使用 useReducer 和 useContext,因为我只是将所有内容订阅到这个 reducer 并将其用作一个巨大的全局状态设置函数。我应该以不同的方式处理这个问题吗?

const initialState : IStore = { isLoading : true,isSignedIn : false,newUser : false,hero : null,alerts : [] };
const store = createContext<IStore>(initialState);
const { Provider } = store;

const StateProvider : React.FC = ( { children } ) => {
  const [state,dispatch] = useReducer((state : IStore,action : IAction) => {

    switch(action.type) {
      case ''TOGGLE LOADING'': {
        const { isLoading } = action.payload;
        if(typeof isLoading === ''undefined''){
          return Object.assign({},state,{ isLoading : !state.isLoading });
        }
        return Object.assign({},{ isLoading });
      }
      case ''SET EXISTING USER INIT DATA'': {
        const { user,hero,gameItems,latestBattle,isSignedIn } = action.payload;
        return { ...state,...{ user,isSignedIn } };
      }
      case ''SET ISSIGNEDIN'': {
        const { isSignedIn } = action.payload;
        return { ...state,isSignedIn };
      }
      case ''SET NEW USER'': {
        const { newUser } = action.payload;
        return { ...state,newUser };
      }
      case ''SET HERO'': {
        const { hero } = action.payload;
        return { ...state,hero };
      }
      case ''SET USER'': {
        const { user } = action.payload;
        return { ...state,user };
      }
      case ''SET ALERTS'': {
        const { alerts }  = action.payload;
        return { ...state,alerts : [...alerts] };
      }
      case ''REMOVE ALERTS'': {
        const { indiciesForRemoval } = action.payload;
        return { ...state,alerts : 
          state.alerts.filter((alert) => {
            return !indiciesForRemoval.includes(alert.index);
          })
        };
      }
      default:
        throw new Error(''In Store default,should not happen.'');
    };
  },initialState);

  return (
    <Provider value={{ state,dispatch }}>
      {children}
    </Provider>
  );
};

解决方法

更多的是代码质量问题:

  • 将所有这些数据和相关操作存储在这个单一的 reducer 中是否有意义?
  • 将reducer 拆分为多个reducer 是否更合乎逻辑和/或可维护?
  • 如果我将这个 reducer 的一部分移动到一个单独的 reducer 中,它可以在其他地方重复使用吗?

如果你只使用一点状态和少量动作,一个reducer就可以了。您必须注意的一件事是重新渲染触发:每当您的减速器的状态更新时,每个使用该减速器的组件都必须重新渲染。对于小国来说,这不是问题,但如果您例如有很多需要 state.fieldA 的复杂组件和很多需要 state.fieldB 的复杂组件,那么它可能值得拆分。否则更新 fieldA 也会触发所有只对 fieldB 感兴趣的组件的重新渲染。 虽然可以进行某些优化以部分抵消这种情况。

React useReducer Hook发射两次/如何将道具传递给reducer?

React useReducer Hook发射两次/如何将道具传递给reducer?

前言/说明

我正在尝试将React的新挂钩函数用于我正在构建的电子商务网站,但是在解决购物车组件中的错误时遇到了问题。

我认为以我想通过使用多个Context组件保持全局状态模块化的事实作为开始讨论的重点。对于我提供的商品类型,我有一个单独的上下文组件,对于一个人的购物车中的商品,我有一个单独的上下文组件。

问题

我遇到的问题是,当我调度将组件添加到购物车的操作时,减速器将运行两次,就像我两次将商品添加到购物车一样。但是仅当它最初被渲染时,或者由于诸如显示之类的奇怪原因而被设置为hidden,然后又返回到block或由于或z-index可能的其他类似更改而发生更改。

我知道这很冗长,但它是一个很挑剔的问题,因此我创建了两个演示该问题的代码笔:

完整的例子

最小的例子

您将看到我包含一个用于切换display组件的按钮。这将有助于展示CSS与问题的相关性。

最后,请用代码笔监视控制台,这将显示所有按钮单击以及每个reducer的哪一部分已运行。该问题在完整示例中最明显,但控制台语句显示的问题在最小示例中也存在。

问题区域

我已查明该问题与以下事实有关:我正在使用useContext挂钩的状态来获取项目列表。调用了一个函数来为我的useReducer钩子生成化简器,但是仅当使用了另一个钩子时才出现,我可以使用像钩子一样不会重新评估的函数,并且没有问题,但是我还需要我以前的上下文中的信息,因此解决方法无法真正解决我的问题。

相关连结

我确定问题不是HTML问题,因此我将不包含我尝试过的HTML修复程序的链接。该问题虽然是由CSS触发的,但并非植根于CSS,因此我也不会包含CSS链接。

我们今天的关于reactjs – 如何在一个状态内合并多个Reducer?react setstate 合并的分享已经告一段落,感谢您的关注,如果您想了解更多关于javascript – ReactJS:如何在Jest中使用action触发reducer、javascript – 如何使用react-redux中的reducer状态更新值的组件状态?、React useContext & useReducer - 需要应用程序中的全局状态,对使用一个或多个 reducer 感到困惑、React useReducer Hook发射两次/如何将道具传递给reducer?的相关信息,请在本站查询。

本文标签: