【问题标题】:React/Redux - Component State not updatingReact/Redux - 组件状态未更新
【发布时间】:2018-02-05 12:15:28
【问题描述】:

似乎我在 React/Redux 中遇到了一个非常常见的问题。有很多人有这个确切的问题,但原因可能会有很大差异,所以我无法确定可能的解决方案。 我正在尝试构建一个网页,其中包含一个可以通过按向上和向下按钮重新排序的列表。

我已经设法追踪更新的状态(数组),直到减速器但组件没有更新。我相信我没有正确更新组件的状态。

这是我的组件:

import React, { Component } from 'react';
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { changeOrder } from "../actions/index.js";

// let list = ["apple", "banana", "orange", "mango", "passion fruit"];

export class Home extends Component {
  constructor(props){
    super(props);
    this.renderList = this.renderList.bind(this);
  }

  goUp(position){
    this.props.changeOrder(position, "up");
  }

  goDown(position){
    this.props.changeOrder(position, "down");
  }

  renderList(fruit){
    const position = this.props.list.indexOf(fruit);
    return (
          <div key={fruit}>
            <li>{fruit}</li>
            <button onClick={() => this.goUp(position)}>Up</button>
            <button onClick={() => this.goDown(position)}>Down</button>
          </div>
        );
  }

  render() {
      return (
        <div>
          <h1>This is the home component</h1>
          <ol>
            {this.props.list.map(this.renderList)}
          </ol>
        </div>
      );
  }
}

function mapStateToProps(state){
  console.log(state);
    return { list: state.list };
}

function mapDispachToProps(dispatch) {
    return bindActionCreators({ changeOrder }, dispatch);
}

export default connect(mapStateToProps, mapDispachToProps)(Home);

行动:

export const GO_UP = "GO_UP";
export const GO_DOWN = "GO_DOWN";

export function changeOrder(position, direction) {
    console.log("position: " + position + " | direction: " + direction);
   switch (direction) {
       case "up": {
           return {
                type: GO_UP,
                payload: position
           };
       }
       case "down": {
           return {
               type: GO_DOWN,
               payload: position
           };
       }
   }
}

减速机:

import { GO_UP, GO_DOWN } from "../actions/index.js";
let list = ["apple", "banana", "orange", "mango", "passion fruit"];

function arrayMove(arr, old_index, new_index) {
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing
}

export default function (state = list, action){
    // debugger;
    switch (action.type){
        case GO_UP: {
            let newState = arrayMove(state, action.payload, action.payload -1);
            console.log(newState);
            return newState;
        }
        case GO_DOWN: {
            let newState = arrayMove(state, action.payload, action.payload +1);
            console.log(newState);
            return newState;
        }
        default: return list;
    }
}

这是 reducer 的 Index.js:

import { combineReducers } from 'redux';
import ReducerList from "./reducer_list";

const rootReducer = combineReducers({
  list: ReducerList
});

console.log(rootReducer);

export default rootReducer;

最后是 index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import ReduxPromise from "redux-promise";

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(ReduxPromise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>
  , document.querySelector('.container'));

任何帮助将不胜感激!

【问题讨论】:

  • 你正在改变状态(你的arrayMove),react-redux connect(特别是maStateToProps)需要更改引用才能更新组件。看到这个以前的答案stackoverflow.com/questions/48475537/…

标签: javascript reactjs redux reducers


【解决方案1】:

当您使用 react-redux 时,您希望确保不会改变状态,而是需要创建一个新的状态对象(浅拷贝)。请参阅here 了解更多信息。如果你改变了之前的状态,Redux 不会知道状态是否已经更新。

在 arrayMove 中,您正在改变当前状态。而不是

arrayMove(state, action.payload, action.payload -1);

使用以下,

arrayMove(state.slice(), action.payload, action.payload -1);

【讨论】:

  • 此解决方案有效。但是,我不确定这是最好的方法。我可能应该更新 arrayMove 函数以返回一个新数组,对吗?
  • 你也可以在arrayMove中创建新的数组。
  • 给其他人的说明:如果您使用lodash.merge 更新状态的方式是,在reducer 中,return {...merge(state, action.payload}(如果您是为简单reducer 组织有效负载结构的类型) .这与使用 const newState = merge(state, action.payload); return newState 不同,因为它不会更新。
【解决方案2】:

问题出在函数arrayMove() 中的reducer 中。您正在更改名为 arr 的现有数组。更改后,React 组件不知道属性 state.list 实际更改了,因为内存引用遵循相同的旧数组(内容已更改)。

要告诉您的应用程序,该列表实际上已更改,您需要返回 NEW 数组。就像你在arrayMove 中的所有逻辑一样,最后你需要返回如下内容:

return [].concat(arr);

在函数式编程术语中,您的 arrayMove 是一个带有副作用的脏函数,因为它通过引用改变了现有的对象/数组。 “clean”函数应该返回一个对象的新实例。

【讨论】:

  • 这个答案也是正确的,感谢您提供的附加信息。 :D
猜你喜欢
  • 2019-05-30
  • 2018-09-25
  • 2021-01-08
  • 1970-01-01
  • 2020-01-16
  • 1970-01-01
  • 2019-06-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多