@reduxjs/toolkit 过滤列表

@reduxjs/toolkit filter list

详细信息:我正在使用@reduxjs/toolkit 和 reactjs 构建一个简单的待办事项应用程序。我使用 @reduxjs/toolkit。我想添加一个筛选列表,按全部和已完成\未完成。

问题:如何将筛选列表添加到此待办事项列表(全部和已完成/未完成)?

todoSlice.js:

import { createSlice } from '@reduxjs/toolkit';

const todoSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [
      {
        id: 1,
        completde: false,
        title: 'todo 1',
        completed: false,
      },
      {
        id: 2,
        completde: true,
        title: 'todo 2',
        completed: false,
      },
    ],
  },
  reducers: {
    addTodo(state, action) {
      state.todos.push({
        id: new Date().toISOString(),
        title: action.payload.title,
      });
    },
    toggleTodo(state, action) {
      const toggleTodoItem = state.todos.find(
        (todo) => todo.id === action.payload.id
      );
      toggleTodoItem.completed = !toggleTodoItem.completed;
    },
    removeTodo(state, action) {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload.id);
    },
    filterTodo(state, action) {
      // state.filterKey = action.payload.key;
      console.log(action.payload);
    },
  },
});

const { actions, reducer } = todoSlice;

export const { addTodo, removeTodo, toggleTodo, filterTodo } = actions;

export default reducer;

FilterTodo.js:

import { useDispatch } from 'react-redux';
import { filterTodo } from './todoSlice';

export default function TodoFilter({ key }) {
  const dispatch = useDispatch();
  return (
    <>
      <button onClick={dispatch(filterTodo('ALL'))}>All</button>
      <button onClick={dispatch(filterTodo('COMPLETED'))}>Completed</button>
      <button onClick={dispatch(filterTodo('NOT_COMPLETED'))}>
        Not completed
      </button>
    </>
  );
}

TodoList.js:

import TodoItem from './TodoItem';
import { useSelector } from 'react-redux';

export default function TodoList() {
  const todos = useSelector((state) => state.todos.todos);
  return (
    <ul>
      {todos.map((todo) => (
        <TodoItem key={todo.id} {...todo} />
      ))}
    </ul>
  );
}

………………

过滤的几种方法之一是将过滤字符串添加到切片的状态,然后创建一个函数来根据此字符串过滤数组,以避免拼写错误我喜欢添加一个包含所有可能过滤器的对象好吧,如果您使用的是打字稿,它可以是 enum 而不是对象。看一看:

todoSlice.js:

import { createSlice } from '@reduxjs/toolkit';

// the object to represent the filters
export const filters = {
  ALL: "ALL",
  COMPLETED: "COMPLETED",
  NOT_COMPLETED: "NOT_COMPLETED"
}

const todoSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [
      {
        id: 1,
        completde: false,
        title: 'todo 1',
        completed: false,
      },
      {
        id: 2,
        completde: true,
        title: 'todo 2',
        completed: false,
      },
    ],

    // default: show all todos
    filterBy: filters.ALL
  },
  reducers: {
    addTodo(state, action) {
      state.todos.push({
        id: new Date().toISOString(),
        title: action.payload.title,
      });
    },
    toggleTodo(state, action) {
      const toggleTodoItem = state.todos.find(
        (todo) => todo.id === action.payload.id
      );
      toggleTodoItem.completed = !toggleTodoItem.completed;
    },
    removeTodo(state, action) {
      state.todos = state.todos.filter((todo) => todo.id !== action.payload.id);
    },
    filterBy(state, action) {
      state.filterBy = action.payload
    },
  },
});

const { actions, reducer } = todoSlice;

export const { addTodo, removeTodo, toggleTodo, filterBy } = actions;

export default reducer;

FilterTodo.js:

import { useDispatch } from 'react-redux';
import { filterBy, filters } from './todoSlice';

export default function TodoFilter({ key }) {
  const dispatch = useDispatch();
  return (
    <>
      // use the filters object to dispatch the right payload
      <button onClick={dispatch(filterBy(filters.ALL))}>All</button>
      <button onClick={dispatch(filterBy(filters.COMPLETED))}>Completed</button>
      <button onClick={dispatch(filterBy(filters.NOT_COMPLETED))}>
        Not completed
      </button>
    </>
  );
}

TodoList.js:

import TodoItem from './TodoItem';
import { useSelector } from 'react-redux';

// don't forget to change the path
import { filters } from 'path/to/todoSlice';
export default function TodoList() {
  const todos = useSelector((state) => state.todos.todos);
  const filter = useSelector((state) => state.todos.filterBy);
  
  // the function to handle the filter logic
  const filteredTodo = () => {
    if(filter === filters.COMPLETED) {
      return todos.filter(todo => todo.completed);
    }
    if(filter === filters.NOT_COMPLETED) {
      return todos.filter(todo => !todo.completed)
    }
    // if none of above return all todos
    return todos;
  }

  return (
    <ul>
      {filteredTodo().map((todo) => (
        <TodoItem key={todo.id} {...todo} />
      ))}
    </ul>
  );
}