2016-07-19 28 views
0

我想弄清楚如何在數據準備好時填充/渲染組件?基本上,我有一個腳本,查詢我的服務器返回數據,然後我解析它,並使其與我需要的屬性集合。然後在另一個文件中,我有反應組件查找該對象,但它們同時運行,因此組件查找時該對象不存在。如何在數據準備好時渲染組件?

我不確定如何繼續。

這是我的組件:

let SliderTabs = React.createClass({ 
    getInitialState: function() { 
     return { items: [] } 
    }, 
    render: function() { 
     let listItems = this.props.items.map(function(item) { 
      return (
       <li key={item.title}> 
        <a href="#panel1">{item.title}</a> 
       </li> 
      ); 
     }); 

    return (
      <div className="something"> 
       <h3>Some content</h3> 
        <ul> 
         {listItems} 
        </ul> 
      </div> 
     ); 
    } 
}); 

ReactDOM.render(<SliderTabs items={home.data.slider} />,     
    document.getElementById('slider-tabs')); 

如何我得到我的數據:

var home = home || {}; 

home = { 
    data: { 
    slider: [], 
    nav: [] 
    }, 
    get: function() { 

    var getListPromises = []; 

    $.each(home.lists, function(index, list) { 
     getListPromises[index] = $().SPServices.SPGetListItemsJson({ 
     listName: home.lists[index].name, 
     CAMLViewFields: home.lists[index].view, 
     mappingOverrides: home.lists[index].mapping 
     }) 
     getListPromises[index].list = home.lists[index].name; 
    }) 

    $.when.apply($, getListPromises).done(function() { 
     home.notice('Retrieved items') 
     home.process(getListPromises); 
    }) 
    }, 
    process: function(promiseArr) { 
    var dfd = jQuery.Deferred(); 

    $.map(promiseArr, function(promise) { 
     promise.then(function() { 
     var data = this.data; 
     var list = promise.list; 

     // IF navigation ELSE slider 
     if (list != home.lists[0].name) { 
      $.map(data, function(item) { 
      home.data.nav.push({ 
       title: item.title, 
       section: item.section, 
       tab: item.tab, 
       url: item.url.split(",")[0], 
       path: item.path.split("#")[1].split("_")[0] 
      }) 
      }) 
     } else { 
      $.map(data, function(item) { 
      home.data.slider.push({ 
       title: item.title, 
       url: item.url.split(",")[0], 
       path: item.path.split("#")[1] 
      }) 
      }) 
     } 
     }) 
    }) 

    console.log(JSON.stringify(home.data)) 
    dfd.resolve(); 
    return dfd.promise(); 
    } 
} 

$(function() { 
    home.get() 
}) 
+0

你看過Redux嗎?這是跟蹤狀態和使用數據的最簡單方法 – erichardson30

+0

我還沒有真正的,我今天才開始看React,所以我還沒有太熟悉。 – Batman

+0

準備好數據後,只需使用'setState'。應該那麼簡單。不要進入Redux。初學者並不需要它。 React總是提到,渲染應該是'props'(external)+'state'(internal)的函數。 – activatedgeek

回答

0

應測試數據收集的長度。如果集合爲空,則返回一個佔位符(例如裝入輪)。在其他情況下,您可以照常顯示數據收集。

const SliderTabs = ({items}) => { 
    let listItems = <p>Loading data...</p> 

    if(items.length != 0) 
     listItems = items.map(item => 
      <li key={item.title}> 
       <a href="#panel1">{item.title}</a> 
      </li> 
     ) 

    return (
     <div className="something"> 
      <h3>Some content</h3> 
       <ul> 
        {listItems} 
       </ul> 
     </div> 
    ) 
} 

ReactDOM.render(
    <SliderTabs items={home.data.slider} />,     
    document.getElementById('slider-tabs') 
) 

我有使用功能的方式來定義一個陣營組成部分,它是推薦的方式,而你並不需要的狀態,裁判或生命週期methodes的。

如果您想在ES6類或React.createCompnent中使用它(請避免),只需使用該函數作爲渲染函數即可。 (不要忘記提取items形式的道具)


編輯:通過讀取新的答案,我已經意識到我還沒有完全回答。

如果您希望在加載數據時更新視圖,則必須集成更多的數據獲取代碼。 React中的基本模式是將組件分爲兩類:容器組件和演示組件。

Containers將只處理邏輯並獲取有用的數據。另一方面,演示組件將只顯示容器給出的數據。

這裏一個小例子:(try it on jsfidle)

測試實用

var items = [{title: "cats"},{title: "dogs"}] 

//Test function faking a REST call by returning a Promise. 
const fakeRest =() => new Promise((resolve, reject) => 
    setTimeout(() => resolve(items), 2000) 
) 

容器組件

//The Container Component that will only fetch the data you want and then pass it to the more generic Presentational Component 
class SliderTabList extends React.Component { 
    constructor(props) { // 
    super(props) 
    //You should always give an initial state (if you use one of course) 
    this.state = { items : [] } 
    } 

    componentDidMount() { 
    fakeRest().then(
     items => this.setState({ items }) //Update the state. This will make react rerender the UI. 
    ) 
    } 

    render() { 
    //Better to handle the fact that the data is fetching here. 
    //This let the Presentational Component more generic and reusable 
    const {items} = this.state 
    return (
     items.length == 0 
     ? <p>Loading Data...</p> 
     : <List items={items} /> 
    ) 
    } 
} 

表象組件

//The Presenational Component. It's called List because, in fact, you can reuse this component with other Container Component. Here is power of React. 
const List = ({items}) => { 
    //Prepare the rendering of all items 
    const listItems = items.map(item => 
     <li key={item.title}> 
     <a href="#panel1">{item.title}</a> 
     </li> 
    ) 

    //Simply render the list. 
    return (
     <div className="something"> 
     <h3>Some content</h3> 
      <ul> 
      {listItems} 
      </ul> 
     </div> 
    ) 
} 

渲染應用

//Mount the Container Component. It doesn't need any props while he is handling his state itself 
ReactDOM.render(
    <SliderTabList />,     
    document.getElementById('slider-tabs') 
) 

而不是檢查長度不爲0,也可以在狀態初始化itemsnull,以便能夠從空區分取數據數據。另一種常用的方法是將一個標誌(一個布爾型在fetchingData int狀態)放在一個數據庫中,以知道數據是否被獲取。但是,在很多文章中,通常建議儘可能使用狀態,然後根據它來計算所需的全部內容。所以在這裏,我要求你檢查長度或null

+0

它是否繼續檢查它自己? – Batman

+0

我在小提琴中試過這個是沒有等待數據的更基本的實現,不起作用。 https://jsfiddle.net/69z2wepo/49604/ – Batman

+0

對不起,我忘記刪除括號:https://jsfiddle.net/69z2wepo/49615/ –

-2

通常情況下,您會安排對OnLoad事件的響應,一旦數據加載完成,它將「觸發」。

我Emrys同意你的代碼應該準備,以測試是否有可用的數據還沒有,並在最初的抽獎「做一些合理的」(當它可能不是)。但是,不,您不會「輪詢」以查看數據是否已到達: 而是您安排在事件觸發時收到通知。那時,您會(例如)重新繪製 UI組件以反映信息。

我好心請您看看陣營文檔,以瞭解該通知究竟是如何完成的?

0

Here是陣營的做這些類型的東西,TL的方式交代;博士 - 立即呈現組件和要麼顯示加載指示器直到數據準備就緒,要麼從render方法返回null

+0

您發送的鏈接顯示如果組件本身正在加載數據,但我收到我的數據並將其存儲在反應之外,那麼該鏈接將顯示如何執行此操作。 – Batman

+0

我會說它更高效地創建一個組件,併爲其中的數據留下佔位符,並在數據到達時填充它們,而不是等到ajax請求完成後再等待組件創建和呈現。認爲行爲應該是異步的。 – Igorsvee

1

在React中執行此操作的常見方法是跟蹤數據何時被提取。這可以通過例如在你的國家有isFetching場:

this.setState({ isFetching: true }); 

最後,當數據到達:

// This would be your default state 
this.state = { 
    isFetching: false 
}; 

然後,當你火了請求(最好是在componentDidMount)您使用設置isFetching爲真,再次將其設置爲false:

this.setState({ isFetching: false }); 

現在,在您的渲染功能,你可以做這樣的事情:

render() { 
return (
    <div className="something"> 
     <h3>Some content</h3> 
     {this.state.isFetching ? <LoadingComponent /> : (
     <ul> 
      {listItems} 
     </ul> 
    )} 
    </div> 
) 
} 

使用狀態時,你不必擔心告訴你的組件做一些事情,而是到做出反應的狀態變化,並呈現它相應。

更新:

如果你打算實際使用反應,我建議你改變你的方法成什麼樣,我上面描述(在the React docs更多)。也就是說,將您在get函數中的代碼移動到您的React組件的componentDidMount函數中。如果這是不可能的,您可能只需等待致電

ReactDOM.render(
    <SliderTabs items={home.data.slider} />,     
    document.getElementById('slider-tabs') 
); 

直到您的數據到達。

+0

你在哪裏放置'this.state'和'setState'? 'home.get()'不會改變狀態嗎?我不確定'home.get()'如何改變組件狀態標誌。除非它是全球性的? – Batman

+0

如果你真的不想使用React獲取數據(我建議你儘可能做),那麼你就不能使用我描述的。看到我更新的答案。 – tobiasandersen

0

將數據加載到父組件中,以便在數據加載時更新組件的道具。

使用默認道具而不是默認狀態,因爲在您的示例中您根本沒有使用狀態。更換「getInitialState」與此:

getDefaultProps: function() { 
    return { 
     items: [] 
    }; 
    } 
0

我獲得了一些答案,但我仍然有很多的麻煩了解如何完成了我的要求。我知道我應該使用組件檢索數據,但我目前對React沒有足夠的瞭解。我顯然需要花費更多的時間學習,但現在我用這個去:

從本質上講,我加了屬性ready到我家對象:

home.ready: false, 
home.init: function() { 
     // check if lists exist 
     home.check() 
     .then(home.get) 
     .then(function() { 
      home.ready = true; 
     }) 
    } 

然後我用componentDidMountsetTimeout檢查時數據準備好,結果設置爲this.state

let SliderTabs = React.createClass({ 
    getInitialState: function() { 
     return {items:[]} 
    }, 
    componentDidMount: function() { 
     let that = this; 

     function checkFlag() { 
      if(home.ready == false) { 
       window.setTimeout(checkFlag, 100); /* this checks the flag every 100 milliseconds*/ 
      } else { 
       that.setState({items: home.data.slider}) 
      } 
     } 
     checkFlag(); 
    }, 
    render: function() { 
     let listItems = this.state.items.map(function(item) { 
      return (
       <li key={item.title}> 
        <a href="#panel1">{item.title}</a> 
       </li> 
       ); 
     }); 

     return (
      <div className="something"> 
       <h3>Some content</h3> 
       <ul> 
        {listItems} 
       </ul> 
      </div> 
      ); 
    } 
}); 

ReactDOM.render(<SliderTabs/>,   
    document.getElementById('slider-tabs')); 

可能不是作出反應的方式,但它似乎工作。