W
W
wakenbyWork2022-02-12 20:36:21
React
wakenbyWork, 2022-02-12 20:36:21

What is the best way to filter a list in react @reduxjs/toolkit?

I am learning react, making a simple todo list with @reduxjs/toolkit, and the question arose of how to filter tasks more correctly.

Application screenshot

6207d8b056d6b600624690.png


todoSlice.jswithout filtering:

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


Option 1 todoSlice.jswith filtering through an additional array with filtered elements:

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


With each interaction with state, two arrays need to be synchronized, the main one and the array with filtered elements, which confuses me.

Option 2 todoSlice.jsfiltering with a value inside an object:

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


In this case, when rendering, you need to check whether the element is valid or not. I like this option better:

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>
  )
}


Which one is more correct? Or is there a better option than these two?

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question