一、深刻淺出React(一)

深刻淺出React(一)

一、create-react-app工具使用

  1. 安裝create-react-apphtml

    npm install create-react-app -g
  2. 建立項目前端

    creact-react-app demos
    cd demos
    npm start
  3. 分解應用

package.jsonnode

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test --env=jsdom",
  "eject": "react-scripts eject"
}

npm start啓動開發環境,npm run build建立生產環境優化代碼,npm test用於測試單元,npm run eject把潛藏在react-scripts中的一序列技術棧「彈射」到
應用的頂端,此命令不可逆且會改變和增長一些文件。react

二、react新的前端思惟模式

  • 數據驅動渲染
  1. 開發者不須要像jQuery同樣詳細的操做DOM着重於‘如何去作’,只須要着重於「我要顯示什麼」,而不用操心「怎樣去作」;
  2. react理念UI = reader(data)
  1. 用戶看到的界面(UI),是一個 純函數(render) 的執行結果,只接受數據(data)做爲參數;
  2. 純函數:沒有任何反作用,輸出徹底依賴於輸入的函數;
  3. 對於react開發者,重要的是區分哪些屬於data,哪些屬於render,要更新界面,要作的就是更新data;
  4. react實踐的也是"響應式編程"的思想。
  • 三、Virtual DOM
  1. 每次render函數被調用,都要把整個組件從新渲染一遍會浪費,而react對此利用Virtual DOM,讓每次渲染都只重新渲染最少的DOM;
  2. DOM樹:HTML是結構化文本,而DOM是結構化文本的抽象表達形式,瀏覽器在渲染HTML格式網頁時,會先將HTML文本解析以構建DOM樹,而後根據DOM樹渲渲染出用戶看到界面,當改變內容時,就去改變DOM樹上的節點;
  3. 雖然DOM樹只是一些簡單的JavaScript語句,但DOM操做會引發瀏覽器對網頁的重新佈局和繪製,因此Web前端開發優化原則之一: 儘可能較少DOM操做
  4. react開發會中jsx語句,將被Babel解析爲建立React組件或HTML元素的語句,但React並不會經過其直接構建或操做DOM樹,而是先構建Virtual DOM;
  5. DOM樹是對HTML的抽象,而Virtual DOM是對DOM樹的抽象;
  6. Vritual DOM不觸及瀏覽器,只存在於JavaScript空間的樹形結構,每次自上而下的渲染React組件時,都會對比這次產生的Vritual DOM和上一次產生的,而後真正的DOM樹只須要操做有差異的部分。
  • 四、JSX
  1. JSX: 是JavaScript的語法擴展,容許咱們在JavaScript中編寫HTML同樣的代碼,最終會編譯成普通的JavaScript語句;
  2. 屬性使用算法

    • 自定義屬性data-*;
    • class和for爲JavaScript保留關鍵字,因此class和for屬性使用className和htmlFor;
  3. JavaScript表達式使用npm

    • JSX容許在閉合標籤中使用JavaScript表達式,但必須用{}包裹;
    • JavaScript表達式要求必須有 返回值 ,因此不能直接使用 if else 語句,但可使用三元操做表達式和&&,||這樣的比較運算符來書寫;
    • 若是確實須要使用 if else語句,能夠寫在函數中,而後在{}中調用。
  4. 樣式編程

    • 經過style屬性定義,單屬性值不能是字符串只能是對象,且屬性名須要使用駝峯命名法(font-size變爲fontSize)。
  5. 註釋json

    • 標籤內注意須要寫在{}中。
  6. 數組數組

    • JSX中的數組會自動展開;
    • 注意若是數組或迭代器中的每一項都是HTML標籤或組件,那麼它們必需要擁有惟一的key屬性,這樣有助於React的DIFF算法,實現最高效的DOM更新。
  7. 事件掛載瀏覽器

    • JSX中能夠經過onClick(HTML原生爲onclick)
    • HTML直接使用onclick缺點:

      1. onclick添加的事件處理函數是在全局環境下執行,污染全局環境,容易產生意想不到的後果;
      2. 給不少DOM元素添加onclick事件,可能會影響網頁的性能;
      3. 對於使用onclick的DOM元素,若是要動態的從DOM樹種刪除,須要把對應的事件處理器註銷,不然可能形成內存泄漏。
    • JSX中的onClick事件(不存在以上問題)

      1. onClick掛載的每一個函數均可以控制在組件中,不會污染全局空間;
      2. JSX中onClick沒有產生直接使用onclick的HTML,而是使用了 事件委託 方式處理,不管有多少個onClick出現,其實最後都只在DOM樹上添加了一個事件處理函數,掛在最頂層的DOM節點上。
      3. 全部的點擊事件都被這個事件處理函數捕獲,而後根據具體組件分配給特定函數,因此性能較高;
      4. 由於React控制了組件的生命週期,在unmount的時候可以清除相關的全部事件處理函數,內存泄漏問題解決。
      function Demo(){
        const name = 'jsx';
        const arr = [
          <h3 key = {0}>數組</h3>
          <p key = {1}>數組會自動展開,注意添加key屬性</p>
        ];
        const func = () => {
          let result = 'hello';
          if (name){
            result += name;
          } else {
            result += 'world';
          }
          return result;
        };
        return (
          <div>
            <h2></h2>
            {/*註釋*/}
            <p style = {{color: 'red',fontSize: '14px'}}>hello {name || 'world'}</p>
            <p className = {name ? 'classA' : 'classB'}>
              hello {name && 'world'}
            </p>
            <p>
              {func()}
            </p>
            {arr}
          </div>
        )
      }

3. React數據

  • React的prop

    1. prop(property的簡寫)是從外部傳遞給組件的數據,一個組件經過定義本身可以接受的prop就定義了本身的對外公共接口;
    2. 每一個React組件都是獨立存在的模塊,組件以外的一切都是外部世界,外部世界就是經過prop來和組件對話的。
    • 給prop賦值

      class Demo extends Component{
        render(){
          return(
            <div>
              <Child caption = "toProp" initValue = {0}/>//給子組件<Child />傳入caption和initValue信息,子組件需定義相關prop接口
            </div>
          )
        }
      }
    • 讀取prop值

      1. this.prop賦值是React.Component構造函數的工做之一;
      2. 若是一個組件須要定義本身的構造函數,必定要在構造函數的第一行super調用父類也就是React.Component的構造函數;
      3. 若是沒有在構造函數中調用super(props),那麼組件實例被構造以後,類實例的全部成員就沒法經過this.props訪問到父組件傳遞過來的props值。
      class Child extends Component{
        constructor(props){
          super(props);
          this.state = {
          //獲取外部傳入的prop,並用於state初始化
            count: props.initValue || 0,
            caption: props.caption
          }
        }
      }
    • propTypes檢查

      1. prop是組件的對外接口,因此一個組件該聲明本身的接口規範,規範組件支持哪些prop,每一個prop該是什麼樣的格式;
      2. React經過propTypes來規範,由於propTypes已經從React包中分離出來,因此新版React中沒法使用React.PropTypes.*,需導入prop-types
        即安裝:npm install prop-type --save導入import PropTypes from ('prop-types')
      3. propTypes驗證器

        1. JavaScript基本類型:

          PropTypes.array

          PropTypes.bool

          PropTypes.func

          PropTypes.number

          PropTypes.object

          PropTypes.string

        2. 能夠被渲染爲子節點的對象,包括數值、字符串ReactElement(指的是JSX中的閉合標籤)或數組:
          PropTypes.node
        3. ReactElement

          PropTypes.element

        4. 指定類的實例

          PropTypes.instanceOf(Message)

        5. 只接受指定的值:

          PropTypes.oneOf(['News','Photos'])

        6. 多個對象類型中的一個:

          PropTypes.oneOfType([
          PropTypes.string,
          PropTypes.number,
          PropTypes.instanceOf(Message)
          ])

        7. 指定類型組成的數組:

          PropTypes.arrayOf(PropTypes.number)

        8. 指定類型的屬性構成的對象:

          PropTypes.objectOf(PropTypes.number)

        9. 符合指定格式的對象:

          PropTypes.shape({
          color: PropTypes.string,
          fontSize: PropTypes.number
          })

        10. 在任意類型上加上isRequired使其不爲空:

          PropTypes.func.isRequired

eg:

Child.propTypes = {
  initValue: PropTypes.number,
  caption: PropTypes.string
  
}
  • React的state
  1. state表明組件的內部狀態,因爲React組件不能修改傳入的prop,因此須要使用state記錄自身數據變化;

    • state初始化

      constructor(props){
       ...
       this.state = {
         count: props.initValue || 0
       }
      }

      注意:使用React.createClass方法建立出來的組件類,經過getInitialState方法獲取初始值,但這種方法已被廢棄。

    • 讀取和更新state

      1. 讀取this.state
      2. 更新this.setState({})

注意:不要直接修改this.state的值,雖然可以改變組件的內部狀態,但只是野蠻的修改了state,卻不會驅動組件重新渲染,因此變化不會反應到界面
而,this.setState()所作的事是先改變this.state的值,而後驅動組件更新

  • prop和state對比

    1. prop用於定義外部接口,state用於記錄內部狀態;
    2. prop的賦值在外部世界使用組件時,state的賦值在組件內部;
    3. 組件不該該改變prop的值,而state的存在就是爲了讓組件來改變。
  • React的context
  1. 使用prop給內部子組件傳遞數據時須要一層一層的傳遞,即便中間有組件不須要使用,這樣比較麻煩;
  2. 使用context能夠實現跨級傳遞。

    • context使用步驟

      1. 父組件經過getChildContext()方法將須要傳入的信息放進context,並聲明childContextTypes(若是不聲明沒法再組件中使用getChildContext());
      2. 要使用的子組件中經過聲明contextTypes(須要和父組件一致)就能夠經過組件實例的context屬性訪問接收到的數據;
      3. 無狀態的組件能夠在函數參數中獲取context;而又狀態的組件能夠經過this.context和生命週期函數獲取context。

eg:
父組件

class Parent extends React.Component{
  getChildContext(){
    return {color: "red"}      
  }
  
  render(){
    return(
      <div>
        <Child />
      </div>
    )
  }
}

Parents.childContextTypes = {
  color: PropTypes.string.isRequired
}
(有狀態)子組件:
class Child extends React.Component{
   render(){
     return(
       <div>
         <p style = {{color:{this.context.color}}}>有狀態的組件能夠經過this.context獲取</p>
         <Grandchild />
       </div>
     )
   }
 }
 
 Child.contextTypes = {
   color: PropTypes.string.isRequired
 }
(無狀態)孫子組件:
function Grandchild(context){
   return(
     <p style = {{color: {context.color}}}>無狀態組件能夠直接在函數的參數中獲取</p>
   )
 }
 
 Grandchild.contextTypes = {
   color:PropTypes.string.isRequired
 }

不積跬步,何以行千里
  • 持續加載中.....
相關文章
相關標籤/搜索