我应该使用模型/类安全地访问状态对象属性吗?

时间:2019-02-18 17:53:15

标签: redux

来自iOS / swift编程世界,我发现访问特定状态属性的通用方法过于通用,我想就此问题发表您的看法

考虑以下Redux状态(可能已经有点嵌套了):

lights: {
    room1: {
        items: {
            1: {
                rgb: false,
                isOn: false,
                value: 50,
                color: -1,
                title: "Desk light"
            },
            2: {
                rgb: false,
                isOn: false,
                value: 50,
                color: -1,
                title: "Groupe 2"
            }
        }
    }
}

和以下选择器:

export const getLight = (state, roomId, itemId) =>
state.lights[roomId].items[itemId];

然后在组件中,将stateToProps与以下内容映射:

function mapStateToProps(state, ownProps) {
    return {
        light: getLight(state, ownProps.roomId, ownProps.itemId)
    };
}

这是(最终)问题所在。

例如,我可以通过this.props.light.isOn访问灯光的不同属性;例如,但是isOn部分不提供任何类型的字符串检查,并且如果我修改状态,则必须更新依赖该属性的所有组件。

我当时正在考虑使用一个Light类,就像这样:

function mapStateToProps(state, ownProps) {
    return {
        light: Light(getLight(state, ownProps.roomId, ownProps.itemId))
    };
}

在React / Redux中是一种好习惯吗?还是在这种情况下还有其他用途?

最后一件事,我还有一个通用操作updateLight,为此我提供了要更新的密钥的字典。再次,我必须注意字典的键,以便它们与状态键完全匹配。 我看不到Light类对我有什么帮助……除非我在另一个枚举中列出密钥,否则将导致大量重复。

谢谢!

2 个答案:

答案 0 :(得分:0)

确保项目中的字段最简单的方法是使用redux存储中的类:

class Light {}

lights: {
    room1: {
        items: {
            1: Light
        }
    }
}

这样,当您使用getLight选择器时,您将获得一个类实例,而不是普通对象。对此类的任何更改将反映在列表中的所有项目中。
如果您想更深入地控制字段及其可能的值,则其他选项(例如TypeScriptFlow)可能更适合您。

在旁注中,您提到商店可能过于嵌套。 Redux建议normalizing you store使其工作起来更类似于关系数据库。

答案 1 :(得分:0)

  

我应该使用模型/类安全地访问状态对象属性吗?

在React中,您的组件可以直接使用映射状态。 为了更新状态,您可以调度将通过reducer处理的动作。

未验证代码

// Reducer.js

// Changes for the state data shape
const initialState = {
  rooms: {
    /*
    room1: {
      items: [
        {
          id: 0, // ID
          rgb: false,
          isOn: false,
          value: 50,
          color: -1,
          title: "Desk light",
          type: "Light", // additional attribute for Item
        },
      ]
    }
    */
  }
};

export const rooms = (state=initialState, action) => {
  switch(action.type) {
    case UPDATE_ITEM:
      const items = [...state.rooms[action.roomId].items];
      let updateItem = items.find(item => item.id === action.itemId);
      // do something with updatedItem
      return {
        ...state.rooms,
        [action.roomId]: {
          items: items.map(item => (
            item.id === action.itemId ? updatedItem : item
          )),
        }
      }
    default:
      return state;
  }
}

// YourComponent.js

function mapStateToProps = (state, ownProps) => {
  const { rooms } = state;
  return {
    rooms,
  };
}

function mapDispatchtoProps = dispatch => {
  return {
    updateItem: (item) => {
      // dispatches UPDATE_ITEM action
      // handled by reducer
      dispatch(updateItem(item));
    }
  };
}

render() {
  const { rooms, updateItem } = this.props;
  return (
    { Object.values(rooms).map(room => (
        <Room key={room.id}>
          { room.items.map(item => (
            <Item key={item.id}
              onChange={() => this.updateItem(item)}
              {...item} // item props
            />
          ))}
        </Room>
    ))}
  );
}

connect(mapStateToProps, mapDispatchToProps)(YourComponent);