代码之家  ›  专栏  ›  技术社区  ›  Scaccoman

React/Redux-组件状态未更新

  •  0
  • Scaccoman  · 技术社区  · 8 年前

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

    我已经设法跟踪更新的状态(数组),直到reducer出现,但组件没有更新。我认为我没有正确更新组件的状态。

    以下是我的组件:

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

    这是减速器的索引。js公司:

    import { combineReducers } from 'redux';
    import ReducerList from "./reducer_list";
    
    const rootReducer = combineReducers({
      list: ReducerList
    });
    
    console.log(rootReducer);
    
    export default rootReducer;
    

    最后是索引。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'));
    

    任何帮助都将不胜感激!

    2 回复  |  直到 8 年前
        1
  •  3
  •   Skyler    8 年前

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

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

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

    使用以下命令,

    arrayMove(state.slice(), action.payload, action.payload -1);
    
        2
  •  1
  •   steppefox    8 年前

    故障位于功能中的减速器中 arrayMove() . 您正在更改名为 arr . 更改后,React组件不知道该属性 state.list 实际上已更改,因为内存引用遵循相同的旧数组(内容已更改)。

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

    return [].concat(arr);
    

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