@wakenbyWork

Как лучше фильтровать список в react @reduxjs/toolkit?

Изучаю react, делаю простой todo list с @reduxjs/toolkit и возник вопрос как правильнее фильтровать задачи.

Скриншот приложения

6207d8b056d6b600624690.png


todoSlice.js без фильтрации:

import { createSlice } from '@reduxjs/toolkit'

const todoSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [],
    todosFilter: [],
    ident: 0,
    keyFilter: 'all'
  },
  reducers: {
    add (state, action) {
      state.todos.push({
        id: state.ident,
        title: action.payload.title,
        completed: false
      })
      
      state.ident = state.ident + 1
    },
    remove (state, action) {
      state.todos = state.todos.filter(todo => todo.id !== action.payload.id)
    },
    toggle (state, action) {
      const editTodo = state.todos.find(todo => todo.id === action.payload.id)
      
      editTodo.completed = !editTodo.completed
    }
  }
})

export const { add, remove, toggle } = todoSlice.actions

export default todoSlice.reducer


Вариант 1 todoSlice.js с фильтрацией через дополнительный массив с фильтрованными элементами:

import { createSlice } from '@reduxjs/toolkit'

function filtered (key, todos) {
  return todos.filter(todo => {
    if (key === 'all') return true
    if (key === 'completed' && todo.completed) return true
    if (key === 'uncompleted' && !todo.completed) return true
  })
}

const todoSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [],
    todosFilter: [],
    ident: 0,
    keyFilter: 'all'
  },
  reducers: {
    add (state, action) {
      state.todos.push({
        id: state.ident,
        title: action.payload.title,
        completed: false
      })
      
      state.todosFilter = filtered(state.keyFilter, state.todos)
      
      state.ident = state.ident + 1
    },
    remove (state, action) {
      state.todos = state.todos.filter(todo => todo.id !== action.payload.id)

      // Фильтрация после удаления
      state.todosFilter = filtered(state.keyFilter, state.todos)
    },
    toggle (state, action) {
      const editTodo = state.todos.find(todo => todo.id === action.payload.id)
      editTodo.completed = !editTodo.completed
      
      // Фильтрация после смены выполнения задачи
      state.todosFilter = filtered(state.keyFilter, state.todos)
    },
    filter (state, action) {
      state.keyFilter = action.payload.key
      state.todosFilter = filtered(state.keyFilter, state.todos)
    }
  }
})

export const { add, remove, toggle, filter } = todoSlice.actions

export default todoSlice.reducer


При каждом взаимодействии со state нужно синхронизировать два массива, основной и массив с фильтрованными элементами, что меня смущает.

Вариант 2 todoSlice.js фильтрация со значением внутри объекта:

import { createSlice } from '@reduxjs/toolkit'

function filtered (key, todo) {
  todo.validFilter = false
  
  if (key === 'all') todo.validFilter = true
  if (key === 'completed' && todo.completed) todo.validFilter = true
  if (key === 'uncompleted' && !todo.completed) todo.validFilter = true
  
  return todo
}

const todoSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [],
    ident: 0,
    keyFilter: 'all'
  },
  reducers: {
    add (state, action) {
      const newTodo = {
        id: state.ident,
        title: action.payload.title,
        completed: false,
        validFilter: false
      }
      
      const modNewTodo = filtered(state.keyFilter, newTodo)
      
      state.todos.push(modNewTodo)
      state.ident = state.ident + 1
    },
    remove (state, action) {
      state.todos = state.todos.filter(todo => todo.id !== action.payload.id)
    },
    toggle (state, action) {
      const editTodo = state.todos.find(todo => todo.id === action.payload.id)
      editTodo.completed = !editTodo.completed

      filtered(state.keyFilter, editTodo)
    },
    filter (state, action) {
      state.keyFilter = action.payload.key
      
      state.todos = state.todos.map(todo => {
        return filtered(state.keyFilter, todo)
      })
    }
  }
})

export const { add, remove, toggle, filter } = todoSlice.actions

export default todoSlice.reducer


В таком случае при рендере нужно проверять валидный ли элемент или нет. Этот вариант мне больше нравиться:

const TodoList = () => {
  const listTodo = useSelector(state => state.todos.todos)
  
  return (
    <ul className='todo-list'>
      { listTodo.map(todo => {
          if (todo.validFilter === false) return null
        
          return <TodoItem key={todo.id} {...todo} />
        })
      }
    </ul>
  )
}


Какой из них более правильнее? Или есть вариант лучше этих двух?
  • Вопрос задан
  • 898 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы