【react】關於react框架使用的一些細節要點的思考


 

( _(:3 」∠)_給園友們提個建議,無論是API文檔還是書籍,一定要多看幾遍!特別是隔一段時間后,會有意想不到的收獲的)
 
這篇文章主要是寫關於學習react中的一些自己的思考:
 
1.setState到底是同步的還是異步的?
2.如何在子組件中改變父組件的state
3.context的運用,避免“props傳遞地獄”
4.組件類里有私有變量a,它到底改放在this.a中還是this.state對象中(作為屬性a)呢?
 

setState到底是同步的還是異步的?

class MyComponent extends React.Component{
   constructor(props) {
     super(props)
     this.state ={
     value:0
        }
   }
handleClick = () => {
      this.setState({value:1})
           console.log('在handleClick里輸出' + this.state.value);
}
render(){
           console.log('在render()里輸出' + this.state.value);
return (<div>
          <button onClick ={this.handleClick}>按鈕</button>
        </div>)
      }
}
export default MyComponent
//省略渲染過程,下面也一樣
 
在這里我們點擊按鈕時,調用handleClick函數,首先調用this.setState()設置value,隨即把this.state.value輸出,結果是什么?
你可能會想,這還不簡單——“在handleClick里輸出1”唄,然而你錯了,它的結果為:
 
事實上,setState()的調用大多數時候是異步的,這意味着,雖然你調用了setState({value:0}),但this.state.value並不會馬上變成0,而是直到render()函數調用時,setState()才真正被執行。結合圖說明一下:
 
你可能又會問了:要是我在render()前多次調用this.setState()改變同一個值呢?(比如value)
 
我們對handleClick做一些修改,讓它變得復雜一點,在調用handleClick的時候,依次調用handleStateChange1 ,handleStateChange2,handleStateChange3,它們會調用setState分別設置value為1,2,3並且隨即打印
handleStateChange1 = () => {
       this.setState({value:1})
       console.log('在handleClick里輸出' + this.state.value);
}
handleStateChange2 = () => {
       this.setState({value:2})
       console.log('在handleClick里輸出' + this.state.value);
}
handleStateChange3 = () => {
       this.setState({value:3})
       console.log('在handleClick里輸出' + this.state.value);
}
handleClick = () => {
      this.handleStateChange1();
      this.handleStateChange2();
      this.handleStateChange3();
}
 
那么輸出結果會是什么呢?如果setState總是同步調用的,那么結果顯然為
在handleClick里輸出1
在handleClick里輸出2
在handleClick里輸出3
 
但是結果為:,證明它可能是異步的
 
這下好理解了吧,配合這幅圖:

setSate大部分的時候是異步執行的,但是,在react本身監聽不到的地方,如原生js的監聽里,setInterval,setTimeout里,setState就是同步更新的

關於更多React的異步同步問題請點擊這里

 

如何在子組件中改變父組件的state?

這是我們經常會遇到的問題之一,解決辦法是:在父組件中寫一個能改變父組件state的方法,並通過props傳入子組件中
class Son extends React.Component{
  render(){
       return(<div onClick = {this.props.handleClick}>
                {this.props.value}
              </div>)
          }
}
class Father extends React.Component{
    constructor(props){
          super(props)
          this.state ={
                value:'a'
               }
       }
    handleClick = () => {
         this.setState({value:'b'})
      }
    render(){
         return (<div style ={{margin:50}}>
                     <Son value = {this.state.value} handleClick = {this.handleClick}/>
                 </div>)
         }
}
 
點擊子組件Son,內容由a變成b,說明父組件的state被修改了

context的運用,避免“props傳遞地獄”

 
3.1假設一個比較極端的場景:你需要從你的子組件里調用父父父父父組件的屬性或方法,怎么辦!當組件嵌套層級過深的時候,不斷地傳props作為實現方式簡直就是噩夢!我稱之為“props傳遞地獄”(這個詞是我瞎編的,參考自“回調函數地獄”)
 
我們接下來實現的是這樣一個需求,把gene屬性(基因)從組件GrandFather -->Father --> Son傳遞,如果用props傳遞:
class Son extends React.Component{
  render(){
      return (<h3 style ={{marginTop:30}}>我從我的爺爺那里得到了基因--{this.props.gene}</h3>)
     }
 }
class Father extends React.Component{
  render(){
      return (<Son gene = {this.props.gene}/>)
    }
}
class GrandFather extends React.Component{
  constructor(props) {
     super(props)
     this.state ={
       gene:'[爺爺的基因]'
       }
   }
  render(){
     return (<Father gene = {this.state.gene}/>)
    }
}
demo:
 
【(。・`ω´・)雖然聽起來有點怪怪的但是大家別介意哈】
 
實現是實現了,但你想想,假設不是從“爺爺”組件,而是從“太太太太爺爺”組件傳下來,這多可怕!不過沒關系,react提供了一個叫做context(上下文)的API,你在頂層組件的context中定義的屬性,可以在所有的后代組件中,通過this.context.屬性去引用!讓我們一睹為快:
class Son extends React.Component{
   render(){
      console.log(this.context.color);
      return (<h3 style ={{marginTop:30}}>我從我的爺爺那里得到了基因--{this.context.gene}</h3>)
      }
}
Son.contextTypes ={
      gene:React.PropTypes.string
}
class Father extends React.Component{
   render(){
      return (<Son/>)
      }
}
class GrandFather extends React.Component{
   getChildContext(){
      return {gene:'[爺爺的基因]'}
   }
   render(){
      return (<Father />)
   }
}
GrandFather.childContextTypes = {
      gene: React.PropTypes.string
};
export default GrandFather
demo效果同上!這個時候你發現,我們在<GrandFather>組件和<Father>組件中都沒有向下傳遞props,我們就從最下層的Son組件中獲取了gene屬性,是不是很方便!
 
解釋下代碼:
getChildContext()是你在頂層組件中定義的鈎子函數,這個函數返回一個對象——你希望在后代組件中取用的屬性就放在這個對象中,譬如這個例子中我希望在Son組件中通過this.context.gene取屬性,所以在getChildContext()中返回{gene:'[爺爺的基因]'}
GrandFather.childContextTypes和Son.contextTypes 用於規定頂層組件和取頂層組件context的后代組件的屬性類型
 
【注意】GrandFather.childContextTypes和Son.contextTypes 這兩個對象必須要規定!否則context只能取到空對象!一開始我犯的這個錯誤簡直讓我狂吐三升血。。。。
 
有圖有真相之context和props的區別
 
3.2context是否推薦使用?
雖然上面這個例子說明了context多么好用,但注意:官方並不推薦經常使用它,因為它會讓你的應用架構變得不穩定(官方文檔原話If you want your application to be stable, don't use context),在我看來,為什么在大多數情況下要使用props而不是實現數據流呢,因為props憑借組件和組件間嚴密的邏輯聯系,使得你能夠清晰地跟蹤應用的數據流(it's easy to track the flow of data through your React components with props)當然了,如果你遇到上述的例子的情況,context還是大有裨益的
 
3.3需要改變context中的屬性時候,不要直接改變它,而是使用this.state作為媒介,如果你試圖在頂層組件的state中放入一個可變的屬性你可以這樣做:
getChildContext(){
     return {type:this.state.type}
}
 
3.4在上述我限制gene的類型時候我是這樣寫的:gene: React.PropTypes.string,使用了React內置的React.PropTypes幫助屬性,此時我的版本為 "react": "15.4.2",在15.5的版本后這一幫助屬性被廢棄,推薦使用props-types庫,像這樣:
const PropTypes = require("Prop-Types");
GrandFather.childContextTypes = {
     gene: PropTypes.string
};
 
當然,在這之前你需要npm install prop-types
 

組件類里有私有變量a,它到底改放在this.a中還是this.state對象中(作為屬性a)呢?

這得根據它是否需要實時的重渲染決定,如果該變量需要同步到變化的UI中,你應該把它放在this.state對象中,如果不需要的話,則把它放在this中 (無代碼無demo)
 
【完】--喜歡這篇文章的話不妨關注一下我喲


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM