2017-07-21 40 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是相同的。