React - Child未获得Parent状态

时间:2017-07-02 08:25:15

标签: reactjs

我的孩子组成部分:

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之前被调用?

如何解决这个问题?

4 个答案:

答案 0 :(得分:2)

不,父亲的daily budget将在孩子componentWillMount之前被召唤。 为确保您的数据成功发送给子项,您应该在父componentDidMount而不是componentDidMount中进行axios查询。获取数据并设置状态后,它将重新呈现父项并将获取的数据发送给子项。

答案 1 :(得分:0)

在你的代码中,孩子的道具正在听父母的状态。问题是道具期望一个值传递给孩子,这个值在您的州内不存在,直到您的电话被退回。尝试为要传递的对象设置默认状态。示例如下。

您不应将调用放在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;

答案 2 :(得分:-1)

你的代码有很多bug。所以我已经很好地重写了你的代码。

<强>误

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

<强>更改

  • 正确更改名称。
  • 在父(地址)组件的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;

答案 3 :(得分:-1)

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

有一个&#34;陷阱,&#34;但是:在呈现发生之前,不会返回对获取数据的异步调用。这意味着组件将使用空数据呈现至少一次。 没有办法暂停&#34;渲染等待数据到达。你不能以某种方式从componentWout中的componentWillMount或wrangle返回一个promise。处理此问题的正确方法是设置组件的初始状态,以使其对渲染有效。

当调用componentDidMount时,组件已渲染一次。

实际上,componentDidMount 是调用获取数据的最佳位置,原因有两个:

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

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

  3. 归功于Dave Ceddia post