2017-07-21 41 views
0

它們究竟意味着什麼?如果我理解正確it,計算新的狀態,當我不能使用this.state,除非我通過一個函數作爲第一個參數setState()狀態更新可能是異步的

// Wrong 
this.setState({a: f(this.state)}); 

// Correct 
this.setState(prevState => {return {a: f(prevState)}}); 

但我可以用this.state來決定做什麼:

if (this.state.a) 
    this.setState({b: 2}); 

道具怎麼樣?

// Correct or wrong? 
this.setState({name: f(this.props)}); 

按理我不能指望this.state調用this.setState後改變:

this.setState({a: 1}); 
console.log(this.state.a); // not necessarily 1 

然後,說我有一個用戶列表。以及選擇在那裏我可以做一個用戶當前:

export default class App extends React.Component { 
    ... 

    setCurrentUserOption(option) { 
     this.setState({currentUserOption: option}); 
     if (option) 
      ls('currentUserOption', option); 
     else 
      ls.remove('currentUserOption'); 
    } 

    handleAddUser(user) { 
     const nUsers = this.state.users.length; 
     this.setState(prevState => { 
      return {users: prevState.users.concat(user)}; 
     },() => { 
      // here we might expect any number of users 
      // but if first user was added, deleted and added again 
      // two callbacks will be called and setCurrentUserOption 
      // will eventually get passed a correct value 

      // make first user added current 
      if (! nUsers) 
       this.setCurrentUserOption(this.userToOption(user)); 
     }); 
    } 

    handleChangeUser(user) { 
     this.setState(prevState => { 
      return {users: prevState.users.map(u => u.id == user.id ? user : u)}; 
     },() => { 
      // again, we might expect any state here 
      // but a sequence of callback will do the right thing 
      // in the end 

      // update value if current user was changed 
      if (_.get(this.state, 'currentUserOption.value') == user.id) 
       this.setCurrentUserOption(this.userToOption(user)); 
     }); 
    } 

    handleDeleteUser(id) { 
     this.setState(prevState => { 
      return {users: _.reject(prevState.users, {id})}; 
     },() => { 
      // same here 

      // choose first user if current one was deleted 
      if (_.get(this.state, 'currentUserOption.value') == id) 
       this.setCurrentUserOption(this.userToOption(this.state.users[0])); 
     }); 
    } 

    ... 
} 

是否所有的回調批量更改狀態後順序執行的應用?

關於第二個想法,setCurrentUserOption基本上就像setState。它會將更改排入this.state。即使回調被依次調用,我也不能依靠this.state被以前的回調改變,我能嗎?所以它可能是最好不要提取setCurrentUserOption方法:

handleAddUser(user) { 
    const nUsers = this.state.users.length; 
    this.setState(prevState => { 
     let state = {users: prevState.users.concat(user)}; 
     if (! nUsers) { 
      state['currentUserOption'] = this.userToOption(user); 
      this.saveCurrentUserOption(state['currentUserOption']); 
     } 
     return state; 
    }); 
} 

saveCurrentUserOption(option) { 
    if (option) 
     ls('currentUserOption', option); 
    else 
     ls.remove('currentUserOption'); 
} 

這樣,我得到排隊的改變來currentUserOption是免費的。

+0

只需雙重檢查你是否使用了任何狀態管理框架,如redux或flux?答案可能會有所不同,具體取決於我要去的 – aug

+0

。但現在我想讓它不用'redux'工作。 –

回答

3

你沒有真正問過一個非常具體的問題。 「這意味着什麼」並不是很重要。但是你通常似乎瞭解基礎知識。

有兩種可能的方法調用setState():要麼通過傳遞一個對象來合併到新的狀態,要麼通過傳遞一個函數來返回一個以類似於第一種方式合併的對象。

讓你無論是做:

// Method #1 
this.setState({foo: this.state.foo + 1}, this.someCallback); 

或者這樣:

// Method #2 
this.setState((prevState) => {return {foo: prevState.foo + 1}}, this.someCallback); 

的主要區別是,方法#1,foo將獲得1基於這是任何狀態遞增當您撥打setState()時,在方法#2中,foo將根據增加1,無論以前的狀態是在箭頭fu nction運行。因此,如果您在實際狀態更新之前的「相同」時間發生多個setState()調用,則方法#1可能會衝突和/或基於過時狀態,而在方法#2中它們保證具有最多狀態因爲它們在狀態更新階段一個接一個地同步更新。

下面是一個說明性的例子:


Method #1 JSBIN Example

// Method #1 
class App extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state = {n: 0}; 
    this.increment.bind(this); 
    } 
    componentDidMount() { 
    this.increment(); 
    this.increment(); 
    this.increment(); 
    } 
    increment() { 
    this.setState({n: this.state.n + 1},() => {console.log(this.state.n)}); 
    } 
    render() { 
    return (  
     <h1>{this.state.n}</h1>  
    ); 
    } 
} 

React.render(
    <App />, 
    document.getElementById('react_example') 
); 

在上面:

> 1 
> 1 
> 1 

this.state.n終值:您會在控制檯中看到這將是1。當n的值爲0時,所有的setState()調用都被加入隊列,因此它們都將其簡單地設置爲0 + 1


Method #2 JSBIN Example

// Method #2 
class App extends React.Component { 
    constructor(props) { 
    super(props); 
    this.state = {n: 0}; 
    this.increment.bind(this); 
    } 
    componentDidMount() { 
    this.increment(); 
    this.increment(); 
    this.increment(); 
    } 
    increment() { 
    this.setState((prevState) => {return {n: prevState.n + 1}},() => {console.log(this.state.n)}); 
    } 
    render() { 
    return (  
     <h1>{this.state.n}</h1>  
    ); 
    } 
} 

React.render(
    <App />, 
    document.getElementById('react_example') 
); 

在上面,你會在控制檯中看到這一點:

> 3 
> 3 
> 3 

n的最終值是3。與#1方法一樣,所有的setState()調用都同時入隊。但是,因爲它們使用一個函數來按照最新狀態進行同步更新(包括通過併發狀態更新所做的狀態更改),所以它們按照您的預期正確增加了三次。


現在,爲什麼console.log()顯示方法#2 3三次,而不是123?答案是setState()回調都在React狀態更新階段結束時一起發生,而不是在特定狀態更新發生之後立即發生。所以在這方面,方法#1和#2是相同的。