【问题标题】:Changes to React state within the Component(via mapDispatchToProps) gives error组件内的 React 状态更改(通过 mapDispatchToProps)给出错误
【发布时间】:2017-07-07 15:32:42
【问题描述】:

我正在从这里https://github.com/reactjs/redux/tree/master/examples/todos 关注 Redux 的 Todo 示例

我做了一些小的改动。我在我的待办事项中接受了更多的领域。 {text, time, by} 并在表格中显示这些详细信息。

我想按时间订购这张桌子。对于这个用例,我确实想遵循 redux 模式。为什么要问!

对于像订购这样简单的事情,我不想在状态中添加它。我想在React state itself 中维护这些功能。由于 VisibleTodoList 是一个智能组件,它的状态包含待办事项,我希望能够以我喜欢的方式对其进行重新排序。

我的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 看起来像这样

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

我的 todo.js 看起来几乎一样

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

单击时间列时,我不断收到此错误 Actions must be plain objects. Use custom middleware for async actions.

我做错了什么? 另外我应该遵循什么模式来实现这一点?不偏离 redux 模式太多。我必须使用setState

为了提供更多上下文,我希望拥有一个本地 UI 状态,而不是在 redux 商店中拥有它。就像这里解释的一样 Should you ever use this.setState() when using redux?

更新 1:我明白因为 orderTime 没有调度它抱怨的对象。但我更广泛的问题是我是否必须实现相同的功能。我该怎么做? 如果我理解正确,我将不得不使用setState 来执行此操作。

【问题讨论】:

  • 问题是您使用orderTime() 作为动作创建者,但实际上并非如此。当您单击时间列时,它会调度从orderTime() 返回的任何内容,这不是一个普通对象而是一个数组
  • 是的,正确。我已经编辑了我的问题以反映相同的情况。我明白为什么我会看到错误。我的问题是如何实现这样的目标。

标签: redux react-redux


【解决方案1】:

这是迄今为止我能想到的最好的解决方案!

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

这是 UI 调整(排序、排序和其他操作),我们将其保持在 React 本地状态。这会导致代码更简洁,因为我们的redux state 是干净的并且不会存储所有这些信息。

接受建议/cmets 和更好的答案!

【讨论】:

    猜你喜欢
    • 2021-05-11
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 2022-06-30
    • 2019-01-08
    • 1970-01-01
    • 2020-04-20
    • 2018-09-21
    相关资源
    最近更新 更多