首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对物品列表使用redux的最佳方法是什么?

对物品列表使用redux的最佳方法是什么?
EN

Stack Overflow用户
提问于 2020-07-09 05:01:21
回答 1查看 1.2K关注 0票数 1

我在redux存储中有一个条目列表(从API返回的JSON对象)。这个数据目前是规范化的,所以它只是一个数组。它大约有10-30个对象,每个对象大约有10个属性。

目前,我们有一个顶级容器(使用react redux),它从存储区读取这个列表,在数组上映射,并呈现一个名为ListItem的组件,它基本上需要对象中的3-4个字段来呈现UI。

我们现在对此没有任何性能问题。但是,我想知道为每个列表项设置一个redux容器组件是否有意义?我认为这将需要数据被规范化,并且我们需要将每个对象的唯一id传递给这个容器,然后容器可以从redux存储读取对象?

这个问题来自于Redux的样式指南- https://redux.js.org/style-guide/style-guide#connect-more-components-to-read-data-from-the-store

只是想了解在这个场景中使用redux的推荐方法是什么。

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2020-07-09 08:51:10

,我想知道为每个列表项设置一个redux容器组件是否有意义?

除了可能有更好的性能,还有更好的代码重用。如果在列表中定义了项的逻辑,那么如何重用列表来呈现其他项?

下面是一个示例,其中Item是数据和编辑的组合,如果您要在列表中而不是项目中创建道具,那么所有项目的道具都会被重新创建。

List也不能用作将id传递给Item组件的常规列表。

代码语言:javascript
运行
复制
const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { useMemo } = React;
const { createSelector } = Reselect;
const { produce } = immer;

const initialState = {
  people: {
    data: {
      1: { id: 1, name: 'Jon' },
      2: { id: 2, name: 'Marie' },
    },
    edit: {},
  },
  places: {
    data: {
      1: { id: 1, name: 'Rome' },
      2: { id: 2, name: 'Paris' },
    },
    edit: {},
  },
};
//action types
const SET_EDIT = 'SET_EDIT';
const CANCEL_EDIT = 'CANCEL_EDIT';
const SAVE = 'SAVE';
const CHANGE_TEXT = 'CHANGE_TEXT';
//action creators
const setEdit = (dataType, id) => ({
  type: SET_EDIT,
  payload: { dataType, id },
});
const cancelEdit = (dataType, id) => ({
  type: CANCEL_EDIT,
  payload: { dataType, id },
});
const save = (dataType, item) => ({
  type: SAVE,
  payload: { dataType, item },
});
const changeText = (dataType, id, field, value) => ({
  type: CHANGE_TEXT,
  payload: { dataType, id, field, value },
});
const reducer = (state, { type, payload }) => {
  if (type === SET_EDIT) {
    const { dataType, id } = payload;
    return produce(state, (draft) => {
      draft[dataType].edit[id] = draft[dataType].data[id];
    });
  }
  if (type === CANCEL_EDIT) {
    const { dataType, id } = payload;
    return produce(state, (draft) => {
      delete draft[dataType].edit[id];
    });
  }
  if (type === CHANGE_TEXT) {
    const { dataType, id, field, value } = payload;
    return produce(state, (draft) => {
      draft[dataType].edit[id][field] = value;
    });
  }
  if (type === SAVE) {
    const { dataType, item } = payload;
    return produce(state, (draft) => {
      const newItem = { ...item };
      delete newItem.edit;
      draft[dataType].data[item.id] = newItem;
      delete draft[dataType].edit[item.id];
    });
  }
  return state;
};
//selectors
const createSelectData = (dataType) => (state) =>
  state[dataType];
const createSelectDataList = (dataType) =>
  createSelector([createSelectData(dataType)], (result) =>
    Object.values(result.data)
  );
const createSelectDataById = (dataType, itemId) =>
  createSelector(
    [createSelectData(dataType)],
    (dataResult) => dataResult.data[itemId]
  );
const createSelectEditById = (dataType, itemId) =>
  createSelector(
    [createSelectData(dataType)],
    (dataResult) => (dataResult.edit || {})[itemId]
  );
const createSelectItemById = (dataType, itemId) =>
  createSelector(
    [
      createSelectDataById(dataType, itemId),
      createSelectEditById(dataType, itemId),
    ],
    (item, edit) => ({
      ...item,
      ...edit,
      edit: Boolean(edit),
    })
  );
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(() => (next) => (action) =>
      next(action)
    )
  )
);
const Item = ({ item, dataType }) => {
  const dispatch = useDispatch();
  return (
    <li>
      {item.edit ? (
        <React.Fragment>
          <input
            type="text"
            value={item.name}
            onChange={(e) =>
              dispatch(
                changeText(
                  dataType,
                  item.id,
                  'name',
                  e.target.value
                )
              )
            }
          />
          <button
            onClick={() =>
              dispatch(cancelEdit(dataType, item.id))
            }
          >
            cancel
          </button>
          <button
            onClick={() => dispatch(save(dataType, item))}
          >
            save
          </button>
        </React.Fragment>
      ) : (
        <React.Fragment>
          {item.name}
          <button
            onClick={() =>
              dispatch(setEdit(dataType, item.id))
            }
          >
            edit
          </button>
        </React.Fragment>
      )}
    </li>
  );
};
const createItem = (dataType) =>
  React.memo(function ItemContainer({ id }) {
    const selectItem = useMemo(
      () => createSelectItemById(dataType, id),
      [id]
    );
    const item = useSelector(selectItem);
    return <Item item={item} dataType={dataType} />;
  });

const Person = createItem('people');
const Location = createItem('places');
const List = React.memo(function List({ items, Item }) {
  return (
    <ul>
      {items.map(({ id }) => (
        <Item key={id} id={id} />
      ))}
    </ul>
  );
});
const App = () => {
  const [selectPeople, selectPlaces] = useMemo(
    () => [
      createSelectDataList('people'),
      createSelectDataList('places'),
    ],
    []
  );
  const people = useSelector(selectPeople);
  const places = useSelector(selectPlaces);
  return (
    <div>
      <List items={people} Item={Person} />
      <List items={places} Item={Location} />
    </div>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
代码语言:javascript
运行
复制
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<script src="https://unpkg.com/immer@7.0.5/dist/immer.umd.production.min.js"></script>
<div id="root"></div>

如果您的应用程序具有重复的逻辑,您可能想要将组件拆分到容器和表示中(容器也称为redux中的连接组件)。您可以重新使用容器,但可以更改表示。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62807725

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档