在 react redux 中设置状态时,我可以获得当前对象的索引吗?

Can I get the index of an object am currently at when setting state in react redux?

我正在使用 React redux 开发一个待办事项应用程序,它的初始状态是一个对象 initialState 并且有一个数组 task,它是一个空数组。设置 task 的值时,我似乎无法找到一种方法来获取对象的 当前索引 以将其分配给 id。 我尝试过使用 indexOf()findIndex() 但没有找到处理它的最佳方法。 我希望 id 等于它的对象的索引。 (如果对象在任务数组中的索引 0 处,则该 id 等于 0) 并且当数组更改或具有多个对象时也可以工作。感谢您的帮助,谢谢

这是我的初始状态

export const initialState = {
    task: []
}

这是我的减速机

const manageTodoReducer = (state, action) => {
    switch(action.type) {
        case "ADD_TODO":
            return (
                {
                    ...state,
                    task: [
                        ...state.task, 
                        {
                            name: "This is the name", 
                            id: state.task.findIndex(x => x.name === state.task.name), 
                            complete: false
                    }]
                }
            )

            default:
                return state
            }
        }

您可以使用 state.tasks.length,但是当您有 2 个任务时会中断,删除第一个任务然后添加一个任务(参见示例,您将以 id 为 1 的 2 个任务结束)。

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;

const initialState = {
  tasks: [{ id: 0 }, { id: 1 }],
};
//action types
const ADD_TASK = 'ADD_TASK';
const REMOVE_TASK = 'REMOVE_TASK';
//action creators
const addTask = () => ({
  type: ADD_TASK,
});
const removeTask = (id) => ({
  type: REMOVE_TASK,
  payload: id,
});
const reducer = (state, { type, payload }) => {
  if (type === ADD_TASK) {
    return {
      ...state,
      tasks: state.tasks.concat({ id: state.tasks.length }),
    };
  }
  if (type === REMOVE_TASK) {
    return {
      ...state,
      tasks: state.tasks.filter(({ id }) => id !== payload),
    };
  }
  return state;
};
//selectors
const selectTasks = (state) => state.tasks;
//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 App = () => {
  const tasks = useSelector(selectTasks);
  const dispatch = useDispatch();
  const remove = (id) => dispatch(removeTask(id));
  const add = () => dispatch(addTask());
  return (
    <div>
      <button onClick={add}>Add task</button>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            <pre>{JSON.stringify(task)}</pre>
            <button onClick={() => remove(task.id)}>
              remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<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>

<div id="root"></div>

不建议使用索引,除非你绝对have to并且当你重新订购或从列表中删除项目时永远不要这样做。

我建议制作一个生成 ID 的函数:

//in case you use redux persist and tasks will persist between reloads
const genId = (state) =>
  Math.max(...state.map(({ id }) => id).concat(-1)) + 1;    

//reducer
id: genId(state.tasks),

请参阅下面的工作示例

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;

const initialState = {
  tasks: [{ id: 0 }, { id: 1 }],
};
//action types
const ADD_TASK = 'ADD_TASK';
const REMOVE_TASK = 'REMOVE_TASK';
//action creators
const addTask = () => ({
  type: ADD_TASK,
});
const removeTask = (id) => ({
  type: REMOVE_TASK,
  payload: id,
});
//in case you use redux persist and tasks will persist between reloads
const genId = (state) =>
  Math.max(...state.map(({ id }) => id).concat(-1)) + 1;
const reducer = (state, { type, payload }) => {
  if (type === ADD_TASK) {
    return {
      ...state,
      tasks: state.tasks.concat({
        id: genId(state.tasks),
      }),
    };
  }
  if (type === REMOVE_TASK) {
    return {
      ...state,
      tasks: state.tasks.filter(({ id }) => id !== payload),
    };
  }
  return state;
};
//selectors
const selectTasks = (state) => state.tasks;
//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 App = () => {
  const tasks = useSelector(selectTasks);
  const dispatch = useDispatch();
  const remove = (id) => dispatch(removeTask(id));
  const add = () => dispatch(addTask());
  return (
    <div>
      <button onClick={add}>Add task</button>
      <ul>
        {tasks.map((task) => (
          <li key={task.id}>
            <pre>{JSON.stringify(task)}</pre>
            <button onClick={() => remove(task.id)}>
              remove
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
<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>

<div id="root"></div>