【问题标题】:React Redux how to update a object from arrayReact Redux 如何从数组更新对象
【发布时间】:2017-06-25 15:16:41
【问题描述】:

我对 react 和 redux 很陌生。 我正在尝试使用以下更新减速器中的状态。

  export default function ReducersTodos(state = [], action) {
    switch (action.type) {
      case ADD_TODO:
                state = [...state, {
                        id: state.length? state.length+1: 1,
                        text: action.value,
                        like: 0
                      }]
                 return state
                 break;
      case ADD_LIKE:
              state = state.map(todo => todo.id === action.id ? { ...todo, like: todo.like+1 } : todo)
              return state
              break;
      case DIS_LIKE:
              state = state.map(todo => todo.id === action.id ? { ...todo, like: todo.like-1 } : todo)
              return state
              break;
      default:
        return state
    }
  }

点赞组件

export class Like extends React.Component {
      constructor(props){
        super(props);
        // This binding is necessary to make `this` work in the callback
        this._handleClickAdd = this._handleClickAdd.bind(this);
        this._handleClickSub = this._handleClickSub.bind(this);
      }

      _handleClickAdd = function(e) {
        e.preventDefault();
        this.props.addLike(this.props.task.id);
      }
      _handleClickSub = function(e) {
        e.preventDefault();
        this.props.disLike(this.props.task.id);
      }
      render() {
          return (
                <div>
                  Like {this.props.task.like}
                  <button className="btn btn-primary" onClick={this._handleClickAdd} {...this.props.task.like}>+</button>
                  <button className="btn btn-danger" onClick={this._handleClickSub} {...this.props.task.like}>-</button>
                </div>
          );
      }
    }
    function mapDispatchToProps(dispatch) {
      return {addLike: bindActionCreators(addLike, dispatch),
              disLike: bindActionCreators(disLike, dispatch)}
    }
    //set props
    const mapStateToProps = (state, ownProps) => ({todos : state.todos});

    Like = connect(mapStateToProps, mapDispatchToProps)(Like)

当我尝试点击like 或dislike 按钮时。 它重新渲染了整个列表,UI 看起来很奇怪。 有没有办法只更新数组的一部分而不查看整个数组。

GitHubhttps://github.com/vinaypost/todos 上提供的工作代码

【问题讨论】:

  • “不查看整个数组”是什么意思。你的整个 UI 应该重新渲染是正确的,这就是 React 的工作方式。您可以阻止某些组件重新渲染,但这些是优化,您现在不必担心它。如果整个 UI 看起来很奇怪,那就是其他地方出了问题。你能添加一个 JSbin 或 Codepen 来说明问题吗?
  • 我在Codepen 和JSbin 上上传代码时遇到了一些困难。所以我已经将我的代码上传到 GitHub github.com/vinaypost/todos
  • 有谁知道如何制作稳定的用户界面。

标签: reactjs redux react-redux


【解决方案1】:

哇,这真是太棒了。我克隆了你的 repo,安装它,运行它,检查它输出的日志,设置 redux 开发工具并检查操作和状态变化,仔细检查mapStateToProps,盯着它希望我能注意到一些东西,但我无法弄清楚发生了什么。我可以看到状态正在进入,并且完全按照您的意愿进行更改,但是 ui 正在翻转。

最终我找到了它here,离减速器不远,或者mapStateToProps。

this.props.todos.reverse().map(todo =>
  <TodoSingleLi key={todo.id} task={todo}/>
)

这里的问题是reverse()。来自mdn:

reverse 方法将调用数组对象的元素转置到位,改变数组,并返回对数组的引用。

基本上,除了 reducer 之外,还有其他东西在更新状态,更糟糕的是,not doing so immutably,这解释了所经历的怪异程度。

幸运的是,这很容易解决:

this.props.todos.slice().reverse().map(todo =>
  <TodoSingleLi key={todo.id} task={todo}/>
)

将slice() 添加到链中可以安全地对数组进行变异。来自mdn:

slice 不会改变原始数组。它返回原始数组中元素的浅拷贝。

感谢这个。很高兴找到一个诚实的错误来进行更改。

【讨论】:

    【解决方案2】:

    您可以使用redux-auto 简化您的代码。

    组件:

    import actions from 'redux-auto'
    
    export class Like extends React.Component {
    
      render() {
          const id = this.props.task.id
          return (
                <div>
                  Like {this.props.task.like}
                  <button className="btn btn-primary" onClick={()=>actions.todos.like({id})} {...this.props.task.like}>+</button>
                  <button className="btn btn-danger" onClick={()=>actions.todos.dislike({id})} {...this.props.task.like}>-</button>
                </div>
          );
      }
    }
    //set props
    const mapStateToProps = (state, ownProps) => ({todos : state.todos});
    
    Like = connect(mapStateToProps)(Like)
    

    减速器:

    tod​​os/add.js

    export default function (todos, payload) {
      return [...todos, {  id: todos.length + 1,
                        text: payload.value,
                        like: 0 }];
    }
    

    tod​​os/like.js

    export default function (todos, payload) {
      return todos.map(todo => todo.id === payload.id ? { ...todo, like: todo.like+1 } : todo);
    }
    

    tod​​os/dislike.js

    export default function (todos, payload) {
      return todos.map(todo => todo.id === payload.id ? { ...todo, like: todo.like-1 } : todo);
    }
    

    了解以上来源。 redux-auto 自动创建动作并根据文件结构将它们连接到 reduce。其中文件夹名称成为状态属性的名称。文件夹中的文件是要对状态的该部分执行的操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多