3

I am following the Todo example of redux from here https://github.com/reactjs/redux/tree/master/examples/todos

I have made some minor changes. I am accepting more fields in my todo. {text, time, by} and displaying these details in a table.

I want to order this table by time. I do not want to follow the redux pattern for this use case. Why you ask!

For something as simple as ordering I do not want to add this in the state. I want to maintain these functions within the React state itself. Since the VisibleTodoList is a smart component where its state has the todos I want to be able to reorder it the way I like to so.

My VisibleTodoList.js

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
   case 'SHOW_ALL':
    return todos
   case 'SHOW_COMPLETED':
    return todos.filter(t => t.completed)
   case 'SHOW_ACTIVE':
    return todos.filter(t => !t.completed)
   default:
    throw new Error('Unknown filter: ' + filter)
  }
 }

const orderTime = (todos) => {
 console.log('inside order time!'); //Displays this. comes inside here.
 return todos.filter(t => t.time > 20) //This gives me error!!
}

const mapStateToProps = (state) => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter), // I do not want to add more things to the state. Want to keep it simple. 
})

const mapDispatchToProps =  ({
 onTodoClick: toggleTodo,
 onTimeClick: orderTime //My function defined above to returned filtered todos.
})

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

TodoList.js Looks like this

const TodoList = ({ todos, persons, onTodoClick, completed, onTimeClick}) => (
<div>
 <table>
  <tbody>
   <tr>
    <th>Task Name</th>
    <th 
     onClick={() => onTimeClick(todos)}
     style={{
       textDecoration: completed ? 'line-through' : 'none'
     }}>Time</th>
    <th>By person</th>
   </tr>
   {todos.map(todo =>
    <Todo
      key={todo.id}
      {...todo}
    />
  )}
  </tbody>
 </table>
</div>
)

My todo.js looks almost the same

const Todo = ({ onClick, completed, text, time, by }) => (
  <tr key={text}>
   <td style={{
    textDecoration: completed ? 'line-through' : 'none'}}>{text}</td>
    <td>{time}</td>
    <td>{by}</td>
  </tr>
)

I keep getting this error when I click on Time column Actions must be plain objects. Use custom middleware for async actions.

What am I doing wrong? Also what pattern should I be following to achieve this? Without deviating too much from the redux pattern. Will I have to use setState

To give more context I want to have a local UI state than having it in the redux store. Like explained here Should you ever use this.setState() when using redux?

Update 1: I do understand that because orderTime is not dispatching a object it is complaining. But my broader question if I had to do the achieve the same functionality. How would I have to do it? If I understand correctly I will have to use setState to do this.

Community
  • 1
  • 1
suprita shankar
  • 1,554
  • 2
  • 16
  • 47
  • The issue is that you're using `orderTime()` as an action-creator, but it's actually not. When you click the Time column, it dispatches whatever returns from `orderTime()`, which is not a plain object *but an array*. – Or B Feb 18 '17 at 08:22
  • Yes correct. I have edited my question to reflect the same. I understand why I see the error. My question is how would I achieve something like this. – suprita shankar Feb 18 '17 at 19:54

1 Answers1

0

This is the best solution I could come up with so far!

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'WEIGHT_SORT':
      return _.sortBy(todos, [function(o) { return o.time; }]);
       default:
     throw new Error('Unknown filter: ' + filter)
   }
 }

class TodoList extends React.Component {

  state = { filter: 'SHOW_ALL' }

  handleShow = filter => {
    this.setState({ filter: 'WEIGHT_SORT' })
  }


render(){
  const filteredTodos = getVisibleTodos(todos, this.state.filter)
  return (
    <div>
    <table>
      <tbody>
       <tr>
        <th>Task Name</th>
        <th 
         onClick={() => this.handleShow('SHOW_COMPLETED')}>Time</th>
        <th>By person</th>
       </tr>
       {filteredTodos.map(todo =>
        <Todo
          key={todo.id}
          {...todo}
          onClick={() => this.props.onTodoClick(todo.id)}
        />
       )}
    </tbody>
  </table>
  </div>
  )
}
}

This being UI tweaks(ordering, sorting & other manipulations) we keep it in the React local state. This leads to cleaner code because our redux state is clean and does not store all of this information.

Open to suggestions/comments and a better answer!

suprita shankar
  • 1,554
  • 2
  • 16
  • 47