组件内React状态的更改(通过mapDispatchToProps)会产生错误

时间:2017-02-17 23:38:04

标签: redux react-redux

我正在跟踪来自https://github.com/reactjs/redux/tree/master/examples/todos

的Todo示例

我做了一些小改动。我接受了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来执行此操作。

1 个答案:

答案 0 :(得分:0)

这是迄今为止我能提出的最佳解决方案!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MazeGenerator: MonoBehaviour {

    public GameObject wallObjectRoot;
    public GameObject wallObjectReference;
    public float wallLength = 1.0f;
    public int xSize = 5;
    public int ySize = 5;

    private Vector3 initialPos;

    // Use this for initialization
    void Start ()
    {
        if (wallObjectReference == null || wallObjectRoot == null){
            Debug.LogError("WallHolder properties need to be assigned to MazeGenerator");
        }

        CreateWalls();  
    }

    // Update is called once per frame
    void Update () {

    }

    void CreateWalls()
    {


        initialPos = new Vector3((-xSize / 2) + wallLength / 2, (-ySize / 2) + wallLength / 2);

        //For x axis
        for (int i = 0; i < ySize; i++)
        {
            for (int j = 0; j <= xSize; j++)
            {
                Vector3 spawnPos = new Vector3(initialPos.x + (j * wallLength) - wallLength / 2, 0.0f, initialPos.z + (i * wallLength) - wallLength / 2);
                GameObject wallObject = Instantiate(wallObjectReference, spawnPos, Quaternion.identity);
                wallObject.transform.parent = wallObjectRoot.transform;
            }
        }

        //for y axis
        for (int i = 0; i <= ySize; i++)
        {
            for (int j = 0; j < xSize; j++)
            {
                Vector3 spawnPos = new Vector3(initialPos.x + (j * wallLength), 0.0f, initialPos.z + (i * wallLength) - wallLength);
                GameObject wallObject = Instantiate(wallObjectReference, spawnPos, Quaternion.Euler(0.0f, 90.0f, 0.0f));
                wallObject.transform.parent = wallObjectRoot.transform;
            }
        }

    }
}

这是UI调整(排序,排序和其他操作),我们将其保持在React本地状态。这导致代码更清晰,因为我们的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> ) } } 很干净,并且不存储所有这些信息。

对建议/评论和更好的答案持开放态度!