2015-04-24 23 views
1

假設您有一個顯示寵物資源的Pet組件。您還擁有通過ownerId屬性屬於寵物的所有者資源。您應該在Pet組件的哪個位置加載所有者資源?何時加載與Flux的異步關係

const Pet = React.createClass({ 
    getInitialState() { 
     return { 
      pet: PetStore.get(this.props.petId) 
     }; 
    }, 

    componentDidMount() { 
     PetStore.addChangeListener(this._onChange); 
    }, 

    componentWillUnmount() { 
     PetStore.removeChangeListener(this._onChange); 
    }, 

    render() { 
     var owner; // where should I initiate the ajax request to get owner? 

     return (
      <p>{owner.name}</p> 
     ); 
    }, 

    onChange() { 
     this.setState({ 
      pet: PetStore.get(this.props.petId) 
     }); 
    } 
}); 

回答

1

正如Thilo提到的,React文檔建議您在componentDidMount中執行異步數據加載。在componentDidMount而不是componentWillMount上執行此操作的原因是,如果您在服務器上爲初始頁面加載運行React,並且您不想在服務器上進行Ajax調用,componentWillMount將會得到執行。這就是說,我建議你將數據提取邏輯移動到另一個組件(在React世界中通常稱爲視圖控制器)。這意味着,您不必讓一個組件執行數據提取和渲染,而是有兩個組件。一個責任是獲取數據,另一個是呈現數據。您將該數據作爲道具從視圖控制器組件傳遞給渲染組件。一個小例子是:

var Pet = React.createClass({ 
    render() { 
    return (
     <p>Pet: {this.props.pet.name}</p> 
     <p>Owner: {this.props.owner.name}</p> 
    ); 
    } 
}); 

var PetController = React.createClass({ 
    getInitialState() { 
    return { 
     pet: PetStore.get(this.props.petId), 
     owner: null 
    }; 
    }, 
    componentDidMount() { 
    OwnerStore.getOwner(this.state.pet.ownerId) 
     .then(owner => this.setState({owner: owner})); 
    }, 
    render() { 
    return <Pet pet={this.state.pet} owner={this.state.owner} />; 
    } 
}); 

什麼這種分離給你更簡單和更集中的組件。 Pet組件不必擔心在何處獲取數據,並且可以在其他情況下重用該組件,而其他情況下您可以從PetStore以外的某個位置獲取數據。而PetController組件只關注數據獲取和狀態管理。爲了使Pet組件更簡單,您可以避免渲染它,直到獲取所有者。喜歡的東西:

var PetController = React.createClass({ 
    getInitialState() { 
    return { 
     pet: PetStore.get(this.props.petId), 
     owner: null 
    }; 
    }, 
    componentDidMount() { 
    OwnerStore.getOwner(this.state.pet.ownerId) 
     .then(owner => this.setState({owner: owner})); 
    }, 
    render() { 
    if (this.state.pet && this.state.owner) { 
     return <Pet pet={this.state.pet} owner={this.state.owner} />; 
    } else { 
     return <div className="spinner" />; 
    } 
    } 
}); 

然後你Pet組件不必擔心異步數據讀取,因爲它不會渲染,直到數據是存在的。

+0

這很有道理。我注意到你從你的調用OwnerStore.getOwner返回一個承諾。您不會在動作創建者中發起請求,然後聽取商店更新? – niftygrifty

+0

當然,你可以做到這一點,但這往往會使商店層有點混亂,因爲你必須跟蹤所有組件目前感興趣的內容。而且你還必須跟蹤改變的時間。我發現僅僅告訴我的組件改變了一些東西就更簡單了,並讓組件從商店中再次提取需要的東西。但並非所有人都同意我的觀點,人們對Flux的理解似乎有很多不同。 –

+0

只是一個額外的評論,因爲我已經被它燒了幾次..任何時候你執行一個異步操作,然後更新狀態,請確保你在調用'setState'之前檢查'this.isMounted()=== true'。虛擬DOM節點超過了真正的DOM節點,如果組件未安裝,它將會引發異常 –