首页 文章

将元素推送到数组时,反应setstate不起作用

提问于
浏览
2

我试图将元素推送到组件状态中的对象数组(在react.js中),我调用方法Array.concat返回一个新数组 .

pushDeck(id, name) {
  var newDeck = [{
    id: id,
    name: name
  }];
  console.log("new path should be: ", this.state.path.concat(newDeck));
  this.setState({
    path: this.state.path.concat(newDeck)
  }, () => {
    console.log("setstate callback: ", this.state.path);
  });
}

第一个console.log打印路径数组的正确值,但在调用setstate的回调后,第二个console.log打印一个空数组 . 这就像this.setState什么也没做

有关更多详细信息:我从grandChild组件调用pushDeck,我将函数pushDeck作为组件DeckGallery的prop,并将此函数提供给其子组件之一 . 这是整个主要组成部分:

import React, {Component} from "react";
import Page from "../components/page.jsx";
import Radium from "radium";
import {connect} from "react-redux";
import {getUserInfo} from "../actions/user";
import {successAlert} from "../actions/alerts";
import {fetchUserDecks, deleteUserDeck} from "../actions/deck.js";
import RaisedButton from 'material-ui/RaisedButton';
import CreateUserDeckContainer from "../containers/createUserDeckContainer.jsx";
import DeckGallery from "../components/deckGallery.jsx";
import _ from "lodash";

const style = {
    row1:{
        margin: "5px"
    },
    path:{
        color: "blue",
        cursor: "pointer"
    }
}


class Home extends Component{

    constructor(props){
        console.log("home constructor");
        super(props);
        this.state = {parentId:null, path:[]};
        this.fetchDecks = this.fetchDecks.bind(this);
        this.renderPath = this.renderPath.bind(this);
        this.goToIndex = this.goToIndex.bind(this);
        this.onDelete = this.onDelete.bind(this);
        this.pushDeck = this.pushDeck.bind(this);
    }

    componentWillMount(){
        console.log("will mount");
        this.props.getUserInfo();
    }

    fetchDecks(skip){
        console.log("fetch decks");
        this.props.fetchUserDecks(this.state.parentId, skip, this.state.path);
    }

    goToIndex(pathLastIndex){
        console.log("goto index", this.state.path);
        var limitToDrop = this.state.path.length - pathLastIndex;
        var newPath = _.dropRight(this.state.path, limitToDrop);
        this.setState({path: newPath});
    }

    pushDeck(id, name){
        var newDeck = [{id: id, name: name}];
        console.log("new path should be: ", Array.from(new Set(this.state.path.concat(newDeck))));
        this.setState({path: Array.from(new Set(this.state.path.concat(newDeck)))},
            ()=>{
            console.log("setstate callback: ", this.state.path);
        });
    }

    componentWillUpdate(nextProps, nextState){
        console.log("nextstate: ",  nextState);
    }

    renderPath(){
        return (
            <div>
                <span onClick={()=>this.goToIndex(0)} style={style.path}>Root</span>
                {this.state.path.map((p, i)=>{
                    <span key={(i+1)} onClick={()=>this.goToIndex(i+1)} style={style.path}>{p.name}</span>
                    })
                }
            </div>
        );
    }

    onDelete(deckId){
        console.log("on delete");
        this.props.deleteUserDeck(deckId, this.state.path, ()=>{
            this.props.successAlert("Deck deleted succesfully !");
            this.forceUpdate();
        });
    }

    render(){
        console.log("path at render: ", this.state.path);
        return (
            <Page name="my collection">
                <div className="container">
                    <div style={style.row1} className="row">
                        <div className="col-lg-9  col-sm-6">
                            <h2>Your decks</h2>
                             Path: {this.renderPath()}
                        </div>
                        <div className="col-lg-3 col-sm-6">
                            <CreateUserDeckContainer path={this.state.path}/>
                        </div>
                    </div>
                    <div className="row">
                        <div className="col">
                            <DeckGallery pushDeck={this.pushDeck} onDelete={this.onDelete} path={this.state.path} fetch={this.fetchDecks} decks={this.props.decks}/>
                        </div>
                    </div>
                </div>
            </Page>
        );
    }
}

function mapStateToProps(state){
    return {decks: state.userDecks};
}

export default connect(mapStateToProps, {getUserInfo, fetchUserDecks, deleteUserDeck, successAlert})(Radium(Home));

Update: 我把错误隔离到了这个:

goToIndex(that){
        console.log("path at gotoindex: "+ JSON.stringify(that.state.path));
    }

    renderPath(){
        var that = this;
        console.log("path at renderpath: "+ JSON.stringify(that.state.path));   
        setTimeout(()=>{
            that.goToIndex(that);
        }, 0);
        that.goToIndex(that);
    }

当我调用渲染时,这是在控制台中打印的内容:

path at renderpath: [{"id":"59cec39e3724bc137d935ed5","name":"math"}]
path at gotoindex: [{"id":"59cec39e3724bc137d935ed5","name":"math"}]
path at gotoindex: []

当从setTimeout内部调用goToIndex时打印最后一行,它应该打印与在setTimeout外调用时相同的东西 . 另外,我在componentWillUpdate中放置了一个console.log,以查看状态是否在两次调用中间发生了变化但是没有发生 .

3 回答

  • 0

    试试这个:

    pushDeck(id, name) {
      .....
      .....
      this.setState({
          path: [...new Set([...this.state.path, ...newDeck])],
          () => console.log("setstate callback: ", this.state.path);
       });
     ......
    }
    
  • 0

    this 不受您对回调的影响 .

    使用箭头语法声明您的函数可能会解决问题 .

    检查this answer,我认为这可能会有所帮助 .

  • 1

    问题是我将数组传递给子节点,因为在Javascript数组中通过引用传递子节点正在修改数组!即:子节点正在修改父节点的状态而没有它的监督:p . 解决方案是在将数组传递给子节点之前克隆数组,我使用了Array类中的方法slice()

相关问题