无法在React js中更新深层嵌套子级中的父级状态

时间:2018-03-08 23:00:45

标签: javascript reactjs recursion svg state

我试图使用react组件递归地构造一个树的一个SVG(一个json-object)。 每个节点(树的节点)组件返回其他节点(和边缘),直到不再有子节点。树在我的屏幕上呈现完美。

现在我想使用一个函数计算所有leafe-nodes,我通过props向所有节点传递。当节点没有子节点时,它会在其构造函数中调用该函数。使用此函数,我想使用this.setState增加我的主要组件的this.state.countLeafs。我的树中有leafe节点经常调用该函数(我用console.log检查它)。对于每个叶子节点,函数都被调用,但我的状态不会更新。

我的主要内容:

import React, { Component } from 'react';
import SpecNode from './graphicTreeComponents/SpecNode.js';

class GraphicController extends Component {
    constructor(props){
        super(props);
        this.incLeafs = this.incLeafs.bind(this);

        this.state = ({
            u: {key: "0", x: 100, y: 0, k: 
                    [
                    {key: "1", x: 40, y: 100, k: null},
                    {key: "2", x: 160, y: 100, k: null}
                    ]
                },
            countLeafs: 0
        })
    }
    incLeafs(){
        console.log("leafs++");
        this.setState({countLeafs: this.state.countLeafs + 1});
        console.log(this.state.countLeafs);
    }
    render(props){
        return (
            <div className="GraphicController">
                <SpecNode {...this.state.u} incLeafs={this.incLeafs}/>
            </div>
        );
    }
}
export default GraphicController;

和我的节点组件:

import React, { Component } from 'react';
import Edge from './Edge.js';
import SpecNode2 from './SpecNode.js';

class SpecNode extends Component{

    constructor(props){
        super(props);

        if(!this.props.k){
            this.props.incLeafs();
        }
    }

    render(props){
        return(
            <svg>
                {this.props.k ? 
                    this.props.k.map(e =>
                        <svg>
                            <Edge x1={this.props.x} y1={this.props.y} x2={e.x} y2={e.y} />
                            <SpecNode2 {...e} incLeafs={this.props.incLeafs}/>
                            <circle cx={e.x} cy={e.y} r={5} fill={"lightgrey"} />
                            <text fontSize={7} x={e.x-2} y={e.y+3} fill="black">{e.key}</text>
                        </svg>
                    ) 
                    :
                    null
                }
            </svg>
        );
    }
}
export default SpecNode;

我有什么基础吗?

谢谢

2 个答案:

答案 0 :(得分:0)

你确定leafCount没有更新吗? setState是异步的,但需要回调。您的console.log可能会在您的状态更新之前发生。你应该试试像......

incLeafs(){
    console.log("leafs++");
    this.setState({countLeafs: this.state.countLeafs + 1}, () => {
        console.log(this.state.countLeafs);
    });   
}

在主要组件中,初始化状态时不需要括号。

this.state = {
        u: {key: "0", x: 100, y: 0, k: 
                [
                {key: "1", x: 40, y: 100, k: null},
                {key: "2", x: 160, y: 100, k: null}
                ]
            },
        countLeafs: 0
    }

您还可以尝试将您的函数调用移动到SpecNode组件中的componentDidMount

constructor(props){
    super(props);
}
componentDidMount() {
    if(!this.props.k){
        this.props.incLeafs();
    }
}

答案 1 :(得分:0)

您的方法this.incLeafs未绑定到父组件。因此,当它运行时,this在子节点调用方法时并不代表GraphicController

要么

A)改变你将父类的方法编写成箭头函数的方式,如下所示:incLeafs = () => {...};

B)在某些时候用this.incLeafsHandler = this.incLeafs.bind(this)之类的方法手动绑定方法方法,然后将this.incLeafsHandler作为incLeaf回调传递给SpecNode。 ((我非常不喜欢这个解决方案,但这只是我的偏好。)

C),将其作为道具中的箭头功能传递下来(如<SpecNode ... incLeafs={() => this.incLeafs()} />

箭头函数始终保留this,就像宣布箭头函数时一样。 (选项A和C)

正常函数将根据它们被调用的位置更改this,除非您使用原始方法的绑定副本。 (选项B)