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

Posted

技术标签:

【中文标题】将元素推送到数组时反应setstate不起作用【英文标题】:react setstate not working when pushing elements to array 【发布时间】:2018-03-13 02:09:58 【问题描述】:

我正在尝试将元素推送到处于组件状态的对象数组(在 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 的道具,而这个函数将函数提供给它的一个子组件。这是整个主要组件:

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

更新:我将错误隔离为:

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

当我调用 render 时,控制台会打印出来:

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

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

【问题讨论】:

我认为这不是检查您的状态是否进行了您想要的更改的正确方法。您在这里指的状态可能只是旧状态 @ReiDien 但即使在方法 componentWillUpdate 中的 console.log(nextState) 中 nextState 是第二个参数,函数接收它也会将路径显示为空数组:( 试试这个path: Array.from(new Set(this.state.path.concat(newDeck))) @ReiDien 它的工作方式与旧方式完全相同 您应该看到那里准确地返回了状态。你能把你的组件代码贴在你调用 pushDeck 的地方吗? 【参考方案1】:

this 不受您对回调的看法的约束。

用箭头语法声明你的函数可能会解决这个问题。

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

【讨论】:

它的工作原理是一样的!。我开始认为编译器或反应存在一些错误 能否在回调内外打印this,以确认它们是同一个对象?【参考方案2】:

问题是我将一个数组传递给孩子,并且由于在 javascript 中数组是通过引用传递的,孩子们正在修改数组!,即:孩子们在没有监督的情况下修改了父母的状态:p。解决方案是在将数组传递给孩子之前克隆数组,我为此使用了 Array 类中的方法 slice()

【讨论】:

【参考方案3】:

试试这个:

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

【讨论】:

以上是关于将元素推送到数组时反应setstate不起作用的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历两个对象数组以将匹配值推送到新数组在 React 中不起作用,但在 JS Fiddle 中起作用

将通知从 iOS 推送到 Android 不起作用

在jQuery中将字符串推送到AJAX成功函数中的数组不起作用

react中的setState在react组件中不起作用

webview javascript将值推送到上一页不起作用

在 componentDidMount 上反应本机 setState 不起作用