繁体   English   中英

反应-孩子没有获得家长状态

[英]React - Child not getting Parent state

我的孩子组件:

class AddressList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    componentDidMount() {
        console.log(this.props.state)
        this.setState({
            addresses: this.props.addresses
        })
    }

    render() {
        return (
            <div>
                <p>
                    <i className="text-muted">Adresses</i>
                    <span className="float-right"><i className="fa fa-plus-circle" onClick={this.toggleAddNewAddress.bind(this)}></i></span>
                </p>
                {this.state.addresses ? this.state.addresses.map((item, key) => {
                    return (
                        <span onClick={this.handleAddressClick.bind(this, item)} key={key} style={{"color": "#444D58", "marginRight": "1em"}}>
                            {item.formatted_address}
                        </span>
                    )
                }) : <i>Loading Addresses...</i>}
            </div>
        );
    }
}

export default AddressList;

我的父母组件:

class AddressList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
        };
    }

    componentWillMount() {
         axios({
            url,
            method: 'get',
            headers
        }).then((response) => {
            this.setState({
                data: response.data
            })
        })
    }

    render() {
        return (
            <div>
                <AddressList addresses={this.state.data.addresses}/>
            </div>
        );
    }
}

export default AddressList;

子组件不接收父state.data。 我认为这与组件生命周期有关。 孩子的componentDidMount是否在父母的componentWillMount之前被调用?

如何解决?

不,父级的componentWillMount将在子级的componentDidMount之前调用。 为确保将数据成功发送给子级,您应该在父componentDidMount而不是componentWillMount进行axios查询。 提取数据并设置状态后,它将重新呈现父级并将提取的数据发送给子级。

在您的代码中,孩子的道具正在监听父母的状态。 问题是道具期望一个值传递给子代,而该子代在返回您的调用之前在您的状态中不存在。 尝试为要传递的对象设置默认状态。 下面的例子。

不应将调用放在componentDidMount函数中,因为如果不添加条件,将会发出许多不必要的请求,并且响应和渲染之间的延迟会更大。 在每次重新渲染期间都会调用componentDidMount。

  class AddressList extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                data: {
                    addresses: []
                },
                shouldMakeRequest: true            
            };
        }

        componentWillMount() {
             if(this.state.shouldMakeRequest){
                 axios({
                    url,
                    method: 'get',
                    headers
                }).then((response) => {
                    this.setState({
                        data: response.data
                    })
                });
                this.setState({shouldMakeRequest: false});
            }
        }

        render() {
            return (
                <div>
                    <AddressList addresses={this.state.data.addresses}/>
                </div>
            );
        }
    }

    export default AddressList;

您的代码有很多错误。 因此,我已经很好地重写了您的代码。

误区

  • 您在两个组件中写了相同的名称(AddressList)。
  • 您没有正确调用API。
  • 在这种情况下,您不希望状态保持两个部分。

变化

  • 正确更改名称。
  • 在Parent(Address)组件的componentDidMount方法中调用API。
  • 您的子组件没有需要状态。 所以我删除了状态。 这次看起来像无状态组件。 因此,我已将您的子组件更改为功能组件。
  • 最后,我将axios方法更改为浏览器的API调用默认获取方法。

更改了下面的代码。

// Address - parent component

class Address extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            addresses: null
        };
    }

    render() {
        return (
            <div>
                <AddressList addresses={this.state.data.addresses}/>
            </div>
        );
    }

    componentDidMount() {
        let config = {
            method: 'GET',
            headers: headers
        }
        fetch(url, config).then(response=>{
            response.json().then(res=>{
                console.log(res);
                this.setState({
                    addresses: res.data
                })
            })
        })
    }
}

export default Address;

// AddressList - child component

let AddressList = (props)=>{
    let { addresses } = this.props;
    return (
        <div>
            <p>
                <i className="text-muted">Adresses</i>
                <span className="float-right"><i className="fa fa-plus-circle" onClick={this.toggleAddNewAddress.bind(this)}></i></span>
            </p>
            {
                addresses ? addresses.map((address, key) => {
                    return (
                        <span onClick={this.handleAddressClick.bind(this, address)} key={key} style={{"color": "#444D58", "marginRight": "1em"}}>
                            {address.formatted_address}
                        </span>
                    )
                }) : <i>Loading Addresses...</i>
            }
        </div>
    );
}

export default AddressList;

componentWillMount在组件的第一个渲染之前被调用,因此乍一看它似乎是放置数据获取逻辑的理想场所。

但是,有一个“陷阱”:在呈现发生之前,异步调用将不会返回数据。 这意味着组件将使用空数据至少渲染一次。 无法“暂停”渲染以等待数据到达。 您不能以某种方式从componentWillMount返回诺言或在setTimeout中争执。 处理此问题的正确方法是设置组件的初始状态,以使其对渲染有效。

到componentDidMount被调用时,该组件已被渲染一次。

实际上,基于两个原因,componentDidMount是发出调用以获取数据的最佳位置

  1. 使用DidMount可以清楚地表明,只有在初始渲染之后才会加载数据。 这提醒您正确设置初始状态,因此您不会因未定义状态而导致错误。

  2. 如果您需要在服务器上渲染应用程序,则componentWillMount实际上将被调用两次-一次在服务器上,再一次在客户端上-这可能不是您想要的。 将数据加载代码放入componentDidMount中将确保仅从客户端获取数据。

归功于Dave Ceddia的职位

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM