8

I'm learning React and Redux and followed the tutorial on the Redux site. I'm trying to add a feature that lets user sort the todos by name, date, etc. The problem is the todo list doesn't rerender itself when I sort the array of todos. The state.sortBy is dispatched by different component and it's working. I can clearly see that the array is sorted by logging store.getState() to console. And the component is of course subscribed to the store.

The array changes. When I sort by "date" it's sorted by date. When I sort by "name" it's sorted by name. But the todo list component ignores it and doesn't rerender.

Here's the code for the todo list container component:

import { connect } from 'react-redux'
import TodoList from '../components/TodoList'
import { toggleTodo } from '../actions'

const sortTodos = (todos, sortBy) => {
  switch (sortBy) {
    case "date":
      return todos.sort((a, b) => Date.parse(b.date) - Date.parse(a.date))
    case "name":
      return todos.sort((a, b) => {
        if (a.name < b.name)
          return -1
        if (a.name > b.name)
          return 1
        return 0
      })
    default:
      return todos
  }
}

const mapStateToProps = (state) => ({
  todos: sortTodos(state.todos, state.sortBy)
})

const mapDispatchToProps = (dispatch) => ({
  onTodoClick: (id) => dispatch(toggleTodo(id))
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

And here is the presentational component:

import React from 'react'
import Todo from './Todo'

const TodoList = ({ todos, onTodoClick }) =>
  <ul>
    {todos.map((todo) =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>

export default TodoList

I've tried couple things and I got it working, but I think it's not the correct way to do this. When I appended .slice(0, -1) to the return statement of sortTodos function, the component rerendered.

const sortTodos = (todos, sortBy) => {
  switch (sortBy) {
    case "date":
      return todos.sort((a, b) => Date.parse(b.date) - Date.parse(a.date)).slice(0, -1)
.
.
.

Thanks for help

1 Answer 1

34

sort does inplace array sorting (modifies the array itself). You need to make a copy before sorting. For example

todos.slice(0).sort((a, b) => Date.parse(b.date) - Date.parse(a.date))

or

[...todos].sort((a, b) => Date.parse(b.date) - Date.parse(a.date))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.