Redux:在规范化状态树中切换布尔值的最佳方法是什么?

Redux:在规范化状态树中切换布尔值的最佳方法是什么?,redux,react-redux,normalizr,redux-actions,Redux,React Redux,Normalizr,Redux Actions,我目前正在用React Native开发一个应用程序。应用程序的状态相当复杂,但由于Redux和Normalizer,因此可以进行管理。我现在必须为用户实现一个过滤项目的功能 为了让用户过滤项目,我在normalizer模式中丰富了服务器响应: export const subCategorySchema = new schema.Entity( "subCategories", {}, { idAttribute: "uuid", processStrategy:

我目前正在用React Native开发一个应用程序。应用程序的状态相当复杂,但由于Redux和Normalizer,因此可以进行管理。我现在必须为用户实现一个过滤项目的功能

为了让用户过滤项目,我在normalizer模式中丰富了服务器响应:

export const subCategorySchema = new schema.Entity(
  "subCategories",
  {},
  {
    idAttribute: "uuid",
    processStrategy: entity => {
      const newEntity = Object.assign({}, { name: entity.name, uuid: entity.uuid, chosen: false });
      return newEntity;
    }
  }
);
相应的减速器现在如下所示:

const initialState = {};
const subCategoriesReducer = (state = initialState, action) => {
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const subCategoriesReducer = (state = initialState, action) => {
  switch (action.type) {
    case TOGGLE_ITEM:
      if (action.payload.item.uuid in state) return { ...state, ...action.payload.item };
  }
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const toggleItem = (item, stateKey) => ({
  type: TOGGLE_ITEM,
  payload: {entities: { [stateKey]: item } }
})
const initialState = {};

export const byId = (state = initialState, action) => {
  if (action.payload && action.payload.entities && action.payload.entities.itemClassifications) {
    return {
      ...state,
      ...action.payload.entities.itemClassifications
    };
  } else {
    return state;
  }
};

export const chosen = (state = [], action) => {
  if (action.type === TOGGLE_ITEM && action.meta === ITEM_CLASSIFICATION) {
    if (state.includes(action.payload.uuid)) {
      return state.filter(uuid => uuid !== action.payload.uuid);
    } else {
      return [...state, action.payload.uuid];
    }
  } else {
    return state;
  }
};

const itemClassificationsReducer = combineReducers({
  byId,
  chosen
});

export default itemClassificationsReducer;

export const getAllItemClassificationsSelector = state =>
  Object.values(state.itemClassifications.byId);
export const getAllItemClassificationsNormalizedSelector = state => state.itemClassifications.byId;
export const getChosenItemClassificationsSelector = state => state.itemClassifications.chosen;

export const enrichAllItemClassificationsSelector = createSelector(
  getAllItemClassificationsSelector,
  itemClassifications =>
    itemClassifications.map(val => ({ ...val, stateKey: ITEM_CLASSIFICATION }))
);

export const getItemClassificationsFilterActiveSelector = createSelector(
  getChosenItemClassificationsSelector,
  itemClassifications => itemClassifications.length > 0
);
这些子类别现在使用此SwitchListItem组件显示在UI中,该组件通过选择器获取其项:

import React, { Component } from "react";
import { Switch, Text, View } from "react-native";
import PropTypes from "prop-types";

import styles, { onColor } from "./styles";

export default class SwitchListItem extends Component {
  static propTypes = {
    item: PropTypes.object
  };

  render() {
    const { name, chosen } = this.props.item;
    return (
      <View style={styles.container}>
        <Text style={styles.switchListText}>{name}</Text>
        <Switch style={styles.switch} value={chosen} onTintColor={onColor} />
      </View>
    );
  }
}
这是我的首选解决方案,因为它不需要很多代码

解决方案2:丰富将项目传递到开关列表的选择器:

另一种解决方案是,在使用带有状态键的选择器传递到列表时,丰富对象。然后我可以创建一个使用此键更新状态的操作,如下所示:

const initialState = {};
const subCategoriesReducer = (state = initialState, action) => {
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const subCategoriesReducer = (state = initialState, action) => {
  switch (action.type) {
    case TOGGLE_ITEM:
      if (action.payload.item.uuid in state) return { ...state, ...action.payload.item };
  }
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const toggleItem = (item, stateKey) => ({
  type: TOGGLE_ITEM,
  payload: {entities: { [stateKey]: item } }
})
const initialState = {};

export const byId = (state = initialState, action) => {
  if (action.payload && action.payload.entities && action.payload.entities.itemClassifications) {
    return {
      ...state,
      ...action.payload.entities.itemClassifications
    };
  } else {
    return state;
  }
};

export const chosen = (state = [], action) => {
  if (action.type === TOGGLE_ITEM && action.meta === ITEM_CLASSIFICATION) {
    if (state.includes(action.payload.uuid)) {
      return state.filter(uuid => uuid !== action.payload.uuid);
    } else {
      return [...state, action.payload.uuid];
    }
  } else {
    return state;
  }
};

const itemClassificationsReducer = combineReducers({
  byId,
  chosen
});

export default itemClassificationsReducer;

export const getAllItemClassificationsSelector = state =>
  Object.values(state.itemClassifications.byId);
export const getAllItemClassificationsNormalizedSelector = state => state.itemClassifications.byId;
export const getChosenItemClassificationsSelector = state => state.itemClassifications.chosen;

export const enrichAllItemClassificationsSelector = createSelector(
  getAllItemClassificationsSelector,
  itemClassifications =>
    itemClassifications.map(val => ({ ...val, stateKey: ITEM_CLASSIFICATION }))
);

export const getItemClassificationsFilterActiveSelector = createSelector(
  getChosenItemClassificationsSelector,
  itemClassifications => itemClassifications.length > 0
);

如果你对Redux有丰富的经验,我想读一个答案,最好是自以为是的。另外,如果您认为我在normalizer中丰富数据的方法不好,您可以想出更好的方法,请告诉我!非常感谢您的建议

我是用完全不同的方式做的

我创建了一个数组,用于保存切换项的UUID。因此,我只需要查看该项是否在切换数组中

就这样,

const initialState = {};
const subCategoriesReducer = (state = initialState, action) => {
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const subCategoriesReducer = (state = initialState, action) => {
  switch (action.type) {
    case TOGGLE_ITEM:
      if (action.payload.item.uuid in state) return { ...state, ...action.payload.item };
  }
  if (action.payload && action.payload.entities) {
    return {
      ...state,
      ...action.payload.entities.subCategories
    };
  } else {
    return state;
  }
};
const toggleItem = (item, stateKey) => ({
  type: TOGGLE_ITEM,
  payload: {entities: { [stateKey]: item } }
})
const initialState = {};

export const byId = (state = initialState, action) => {
  if (action.payload && action.payload.entities && action.payload.entities.itemClassifications) {
    return {
      ...state,
      ...action.payload.entities.itemClassifications
    };
  } else {
    return state;
  }
};

export const chosen = (state = [], action) => {
  if (action.type === TOGGLE_ITEM && action.meta === ITEM_CLASSIFICATION) {
    if (state.includes(action.payload.uuid)) {
      return state.filter(uuid => uuid !== action.payload.uuid);
    } else {
      return [...state, action.payload.uuid];
    }
  } else {
    return state;
  }
};

const itemClassificationsReducer = combineReducers({
  byId,
  chosen
});

export default itemClassificationsReducer;

export const getAllItemClassificationsSelector = state =>
  Object.values(state.itemClassifications.byId);
export const getAllItemClassificationsNormalizedSelector = state => state.itemClassifications.byId;
export const getChosenItemClassificationsSelector = state => state.itemClassifications.chosen;

export const enrichAllItemClassificationsSelector = createSelector(
  getAllItemClassificationsSelector,
  itemClassifications =>
    itemClassifications.map(val => ({ ...val, stateKey: ITEM_CLASSIFICATION }))
);

export const getItemClassificationsFilterActiveSelector = createSelector(
  getChosenItemClassificationsSelector,
  itemClassifications => itemClassifications.length > 0
);