2016-07-24 60 views
0

我有一個小反應的應用程序。當選定的dep/arr工作站發生變化時,它會從BART API重新獲取計劃數據。reactjs setState沒有正確更改

由於某些原因舊代碼(見下文)它不能正常工作。我先做了setState然後嘗試使用depStation的新值,但它顯示了以前的值。因此,舉例來說,我重新加載頁面的初始depState值爲SFIA。如果我將值更改爲FRMT,則console.log(selected)顯示爲FRMT,但console.log(this.state.depStation)仍顯示SFIA。如果我再次將其更改爲HAYW,console.log(selected)顯示HAYW,但console.log(this.state.depStation)顯示FRMT。爲了使應用程序的工作,我只是使用selected而不是this.state.depStation,但我想這不是最好的方法。

所以我不太明白爲什麼this.state.depStation顯示調用this.setState({depStation: selected})後的prev數據。可以解釋一下爲什麼會發生這種情況?

這是行不通的舊版本:

reRunFetching(selected, type) { 
    if (type === "depart") { 
    this.setState({depStation: selected}); 
    console.log(selected); //Showing properly what I select 
    console.log(this.state.depStation); //For some reason the previously selected 
    } 
    else if (type === "arrive") { 
    this.setState({arrStation: selected}); 
    } 
    this.fetchingAPI(this.state.depStation, this.state.arrStation) 
} 

新版本。這是工作正常,但我想這不是最好的解決辦法:

reRunFetching(selected, type) { 
    if (type === "depart") { 
    this.fetchingAPI(selected, this.state.arrStation) 
    this.setState({depStation: selected}); 
    console.log(selected, this.state.arrStation); 
    } 
    else if (type === "arrive") { 
    this.fetchingAPI(this.state.depStation, selected) 
    this.setState({arrStation: selected}); 
    console.log(this.state.depStation, selected); 
    } 
} 

index.js的休息

class App extends Component { 
    constructor(props) { 
    super(props); 

    this.state = { 
     schedules: [], 
     depStation: DEP_STATION, 
     arrStation: ARR_STATION 
    }; 

    this.fetchingAPI(this.state.depStation, this.state.arrStation) 
    } 

    fetchingAPI(departureStation, arrivalStation) { 
    fetch("http://api.bart.gov/api/sched.aspx?cmd=depart&orig=" + departureStation + "&dest=" + arrivalStation + "&date=now&key=MW9S-E7SL-26DU-VV8V&b=0&a=4&l=0") 
    .then(function(response) { 
     return response.text();}) 
    .then((responseXML) => { 
     let tripsArray = this.parsingXML(responseXML); 
     this.setState({schedules: tripsArray}); 
    }) 
    .catch((error) => { 
     console.log(error); 
    }); 
    } 

    render() { 
    return (
     <div> 
     <div className="row"> 
      <div className="col-md-5 col-md-offset-1 search-bar"> 
      <SelectDepart onSelectedChange={selected => this.reRunFetching(selected, "depart")}/> 
      </div> 
      <div className="col-md-5 search-bar"> 
      <SelectArrive onSelectedChange={selected => this.reRunFetching(selected, "arrive")}/> 
      </div> 
     </div> 
     <TimeTable schedules={this.state.schedules} /> 
     </div> 
    ) 
    } 

回答

1

的setState()是不會立即設置異步非阻塞的方法新的狀態,如你所期望的那樣。正如文檔所述:

setState()不會立即改變this.state,但會創建一個掛起狀態轉換。調用此方法後訪問this.state可能會返回現有值。
無法保證setState調用的同步操作,並且調用可能會批處理以提高性能。

如果你需要,你可以傳遞一個回調第二個參數對setState(),它會在狀態變化被解僱:

this.setState({depStation: selected}, function() { 
// some code 
}); 
+0

伊利亞,你怎麼看我目前的工作版本?與你的建議相比,這是否更糟/更好? –

+0

如果操作順序setState()和fetchingAPI()不重要(它們是獨立的),那麼你的解決方法就適合了。如果存在或可能引起一些副作用,例如競爭條件,那麼最好調用在傳遞給setState()的回調函數中獲取API()以確保執行順序。 –

0

的setState()是哪個隊列的狀態異步方法。因此爲了在setState之後立即訪問狀態值,需要調用一個回調函數作爲setState方法的第二個參數,該方法將首先設置您的狀態,之後將重新呈現更新狀態的視圖。下面的例子會幫助你。

this.setState({ 
    depStation: selected 
},() => { 
    // here you will get your depStation state value 
    console.log(this.state.depStation,"depStation value") 
});