簡體   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