二、React小書學(xué)習(xí)摘記

React.js 小書學(xué)習(xí) 之 【使用 JSX 描述 UI 信息】

  1. JSX 到頁面 過程圖解:
    JSX 到頁面過程圖解
  2. JSX <=> JavaScript 對象:
    JSX把HTML模板轉(zhuǎn)化為JS對象,使之符合JS語法,所以使用 React 和 JSX 一定會(huì)有編譯過程
  3. React小書總結(jié)(提示注意點(diǎn)):
    1、JSX 是 JavaScript 語言的一種語法擴(kuò)展,JSX 元素就是 JavaScript 對象,長得像 HTML,但并不是 HTML。
    2、React.js 可以用 JSX 來描述你的組件長什么樣的。
    3、JSX 在編譯的時(shí)候會(huì)變成相應(yīng)的 JavaScript 對象描述。
    4、react-dom 負(fù)責(zé)把這個(gè)用來描述 UI 信息的 JavaScript 對象變成 DOM 元素,并且渲染到頁面上。

React.js 小書學(xué)習(xí) 之 【組件的 render 方法】

  1. React.js 中一切皆組件,用 React.js 寫的其實(shí)就是 React.js 組件;
  2. 插值表達(dá)式{}:{} 內(nèi)可以放任何 JavaScript 的代碼,包括變量、表達(dá)式計(jì)算、函數(shù)執(zhí)行等等。

React.js 小書學(xué)習(xí) 之 【組件的組合、嵌套和組件樹】

  1. 自定義的組件都必須要用大寫字母開頭,普通的 HTML 標(biāo)簽都用小寫字母開頭;
  2. 組件樹 圖解:
    組件樹圖解
  3. 數(shù)據(jù)流動(dòng):數(shù)據(jù)在組件樹內(nèi)自上往下流動(dòng);

React.js 小書學(xué)習(xí) 之 【事件監(jiān)聽】

  1. 事件綁定(on*={···}on* 屬性名必須是駝峰命名法
    如:onClick={this.handleClick}
    注:handleClick,事件監(jiān)聽函數(shù),它是當(dāng)前組件類自己的一個(gè)實(shí)例方法
  2. 通常情況下,on* 的事件監(jiān)聽只能用在普通的 HTML 的標(biāo)簽上,而不能用在組件標(biāo)簽上,如果需要能用到組件標(biāo)簽上是需要經(jīng)過特殊處理的;
  3. event 對象:
    1、和普通瀏覽器一樣,事件監(jiān)聽函數(shù)會(huì)被自動(dòng)傳入一個(gè) event 對象,這個(gè)對象和普通的瀏覽器 event 對象所包含的方法和屬性都基本一致;
    2、React.js 將瀏覽器原生的 event 對象封裝了一下,對外提供統(tǒng)一的 API 和屬性,這樣你就不用考慮不同瀏覽器的兼容性問題;
  4. 關(guān)于事件監(jiān)聽函數(shù)中的 this
    1、一般來講,某個(gè)組件類的實(shí)例方法里面的 this 指向 當(dāng)前組件類實(shí)例本身
    但是 事件監(jiān)聽函數(shù) handleClick 里面的 this 并不是,直接輸出會(huì)是 null or undefined
    原因是:React.js 對事件監(jiān)聽函數(shù) handleClick 的調(diào)用并不是通過對象方法的方式調(diào)用的,而是直接通過函數(shù)調(diào)用的,所以 事件監(jiān)聽函數(shù) handleClick 內(nèi)并不能通過 this 獲取到實(shí)例;
    2、基于(1),如果我們需要在 事件監(jiān)聽函數(shù) handleClick 里面使用當(dāng)前實(shí)例的話,我們需要手動(dòng)地將實(shí)例方法 bind 到當(dāng)前實(shí)例上再傳入給 React.js;
    如:onClick={this.handleClick.bind(this)} 這樣就能在 事件監(jiān)聽函數(shù) handleClick 內(nèi)通過 this 獲取到當(dāng)前組件類實(shí)例了;
  5. React小書總結(jié)(提示注意點(diǎn)):
    1、為 React 的組件添加事件監(jiān)聽是很簡單的事情,你只需要使用 React.js 提供了一系列的 on* 方法即可;
    2、React.js 會(huì)給每個(gè)事件監(jiān)聽傳入一個(gè) event 對象,這個(gè)對象提供的功能和瀏覽器提供的功能一致,而且它是兼容所有瀏覽器的;
    3、React.js 的事件監(jiān)聽方法需要手動(dòng) bind 到當(dāng)前組件類實(shí)例,這種模式在 React.js 中非常常用;

React.js 小書學(xué)習(xí) 之 【組件的 state 和 setState】

  1. 一個(gè)組件的顯示形態(tài)是可以由它數(shù)據(jù)狀態(tài) state 和配置參數(shù) props 共同決定的;
  2. setState 方法由父類 Component 所提供。當(dāng)我們調(diào)用這個(gè)函數(shù)的時(shí)候,React.js 會(huì)更新組件的狀態(tài) state,并且重新調(diào)用 render 方法,然后再把 render 方法所渲染的最新的內(nèi)容顯示到頁面上;
  3. 當(dāng)我們要改變組件的狀態(tài)的時(shí)候,不能直接用 this.state = xxx 這種方式來修改,如果這樣做 React.js 就沒辦法知道你修改了組件的狀態(tài),它也就沒有辦法更新頁面。所以,一定要使用 React.js 提供的 setState 方法,它接受一個(gè)對象或者函數(shù)作為參數(shù)
  4. setState 合并
    1、當(dāng)你調(diào)用 setState 的時(shí)候,React.js 并不會(huì)馬上修改 state。而是把這個(gè)對象放到一個(gè)更新隊(duì)列里面,稍后才會(huì)從隊(duì)列當(dāng)中把新的狀態(tài)提取出來合并到 state 當(dāng)中,然后再觸發(fā)組件更新;
    2、在 React.js 內(nèi)部會(huì)把 JavaScript 事件循環(huán)中的消息隊(duì)列的同一個(gè)消息中的 setState 都進(jìn)行合并以后再重新渲染組件,所以在使用 React.js 的時(shí)候,并不需要擔(dān)心多次進(jìn)行 setState 會(huì)帶來性能問題;
  5. 基于(4),setState的合并:
    1、setState 方法接受一個(gè)對象參數(shù) 適用于 僅更新組件狀態(tài) state,后續(xù)操作不依賴前一個(gè) setState 的結(jié)果的情況
    2、setState 方法接受一個(gè)函數(shù)參數(shù) 適用于 后續(xù)操作依賴前一個(gè) setState 的結(jié)果的情況,因?yàn)?React.js 會(huì)把上一個(gè) setState 的結(jié)果傳入這個(gè)函數(shù),你就可以使用該結(jié)果進(jìn)行運(yùn)算、操作,然后返回一個(gè)對象作為更新 state 的對象:
      handleClickOnLikeButton () {
        this.setState((prevState) => {
          // prevState:上一個(gè) setState 的返回值
          return { count: 0 }
        })
        this.setState((prevState) => {
          // 上一個(gè) setState 的返回是 count 為 0,當(dāng)前返回 1
          return { count: prevState.count + 1 } 
        })
        this.setState((prevState) => {
          // 上一個(gè) setState 的返回是 count 為 1,當(dāng)前返回 3
          return { count: prevState.count + 2 } 
        })
        // 最后的結(jié)果是 this.state.count 為 3
      }
    
  6. 更新組件狀態(tài) state ,只需要 setState 對應(yīng)狀態(tài)字段的 key value 即可,無需傳入整個(gè)對象;
      constructor (props) {
        super(props)
        this.state = {
          name: 'Tomy',
          isLiked: false
        }
      }
      handleClickOnLikeButton () {
        this.setState({
          isLiked: !this.state.isLiked
        })
      }
    
    

React.js 小書學(xué)習(xí) 之 【配置組件的 props】

  1. React小書總結(jié)(提示注意點(diǎn)):
    1、為了使得組件的可定制性更強(qiáng),在使用組件(引入組件)的時(shí)候,可以在組件標(biāo)簽上加屬性來傳入配置參數(shù),我們可以把任何類型的數(shù)據(jù)作為組件的參數(shù),包括字符串、數(shù)字、對象、數(shù)組、甚至是函數(shù)等等,這樣一個(gè)組件的樣式和行為都可以用 props 來控制,就可以達(dá)到很好的可配置性;
    2、組件可以在內(nèi)部通過 this.props 獲取到配置參數(shù),組件可以根據(jù) props 的不同來確定自己的樣式和行為,達(dá)到可配置的效果;
    3、可以通過給組件添加類屬性defaultProps 來配置默認(rèn)參數(shù);
    4、props 一旦傳入,你就不可以在組件內(nèi)部對它進(jìn)行修改,但是你可以通過父組件主動(dòng)重新渲染的方式來傳入新的 props,從而達(dá)到更新的效果;

     import React, { Component } from 'react'
     import ReactDOM from 'react-dom'
     import './index.css'
    
    
     class LikeButton extends Component {
         // 定義 默認(rèn)的props配置參數(shù) defaultProps
         static defaultProps = {
             wordings: {
                 likedText: '取消',
                 unlikedText: '點(diǎn)贊'
             }
         }
         
         constructor () {
             super()
             this.state = { isLiked: false }
         }
    
         handleClickOnLikeButton () {
             this.setState({
                 isLiked: !this.state.isLiked
             })
             // 子組建LikeButton 使用 父組件Index 傳遞過來的 props配置參數(shù) 處理行為
             if (this.props.onClick) {
                 this.props.onClick()
             }
         }
    
         render () {
             return (
                 <button onClick={this.handleClickOnLikeButton.bind(this)}>
                     {/* 子組建LikeButton 獲取 父組件Index 傳遞過來的 props配置參數(shù) 處理樣式,獲取后的 props 在子組建中是不可變的,所以就會(huì)有在 父組件Index 中的 handleClickOnChange 方法 */}
                     {this.state.isLiked ? this.props.wordings.likedText : this.props.wordings.unlikedText} ??
                 </button>
             )
         }
     }
    
     class Index extends Component {
         constructor () {
             super()
             // 父組件Index 中初始化參數(shù) wordings
             this.state = {
                 wordings: {
                     likedText: '已贊',
                     unlikedText: '贊'
                 }
             }
         }
    
         // 父組件Index 中處理參數(shù) wordings 的變化,作為處理好的 props 配置參數(shù)傳遞到 子組件LikeButton
         handleClickOnChange () {
             this.setState({
                 wordings: {
                     likedText: '取消',
                     unlikedText: '點(diǎn)贊'
                 }
             })
         }
    
         render () {
             return (
                 <div>
                     <LikeButton
                         // 使用子組件LikeButton 并傳遞 配置參數(shù)到 子組件LikeButton 的 props
                         // 在這里 wordings 定義子組建樣式,傳入的是 對象;  onClick 定義子組建行為,傳入的是 函數(shù)
                         wordings={this.state.wordings}
                         onClick={() => console.log('Click on like button!')}/>
                     <div>
                         <button style={{marginTop: 20 + 'px'}} onClick={this.handleClickOnChange.bind(this)}>
                             修改 wordings
                         </button>
                     </div>
                 </div>
             )
         }
     }
    
     ReactDOM.render(
         <Index />,
         document.getElementById('root')
     )
    

React.js 小書學(xué)習(xí) 之 【state vs props】

  1. state vs props:http://huziketang.mangojuice.top/books/react/lesson12
    注:上面鏈接已經(jīng)把兩者的區(qū)別介紹得比較詳盡了,還特意說明了函數(shù)式組件的編寫方式

React.js 小書學(xué)習(xí) 之 【渲染列表數(shù)據(jù)】

  1. 如果你往 JSX 插值表達(dá)式 {} 中放一個(gè)數(shù)組,React.js 會(huì)幫你把數(shù)組里面一個(gè)個(gè)元素羅列并且渲染出來;

  2. 使用 map 渲染列表數(shù)據(jù){ users.map( (user, i) => <User key={i} user={user}/> ) }
    注:這里的 key 僅僅只是作為每個(gè)元素的唯一標(biāo)識(shí),雖然寫法上同 props 傳參一樣,但并不是 props 的一員,不能作為 propsUser這個(gè)子組件中使用,若在 User 子組件使用,會(huì)發(fā)生以下錯(cuò)誤,其 key 值為 undefined

     class Lesson extends Component {
         handleClick (props, e) {
             console.log(props.key); // undefined, 不能作為 props 使用
             console.log(props.index + '-' + props.lesson.title);
         }
    
         render () {
             const { key, index, lesson } = this.props;
             return (
                 <div onClick={this.handleClick.bind(this, { key, index, lesson })}>
                     <h1>{lesson.title}</h1>
                     <p>{lesson.description}</p>
                 </div>
             );
         }
     }
    
將 key 作為 props 使用的報(bào)錯(cuò)信息
  1. 對于用表達(dá)式套數(shù)組羅列到頁面上的元素,都要為每個(gè)元素加上 key 屬性,這個(gè) key 必須是每個(gè)元素唯一的標(biāo)識(shí)。標(biāo)準(zhǔn)做法(最好),key 的值可以直接用后臺(tái)數(shù)據(jù)返回的 id,因?yàn)楹笈_(tái)的 id 都是唯一的;

     import React, { Component } from 'react'
     import ReactDOM from 'react-dom'
     import './index.css'
    
     const users = [
         { username: 'Jerry', age: 21, gender: 'male' },
         { username: 'Tomy', age: 22, gender: 'male' },
         { username: 'Lily', age: 19, gender: 'female' },
         { username: 'Lucy', age: 20, gender: 'female' }
     ]
    
     class User extends Component {
         render () {
             const { user } = this.props;
             return (
                 <div>
                     <div>姓名:{user.username}</div>
                     <div>年齡:{user.age}</div>
                     <div>性別:{user.gender}</div>
                     <hr/>
                 </div>
             )
         }
     }
    
     class Index extends Component {
         render () {
             return (
                 <div>
                     { users.map( (user, i) => <User key={i} user={user}/> ) }
                 </div>
             )
         }
     }
    
     ReactDOM.render(
         <Index />,
         document.getElementById('root')
     )
    

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(一)】

  1. React.js 中一切都是組件,用 React.js 構(gòu)建的功能其實(shí)也就是由各種組件組合而成;
  2. 組件的劃分沒有特別明確的標(biāo)準(zhǔn),劃分組件的目的性是為了代碼可復(fù)用性、可維護(hù)性;
  3. 我們遵循一個(gè)原則:如果一個(gè)文件導(dǎo)出的是一個(gè)類,那么這個(gè)文件名就用大寫開頭;
  4. 構(gòu)建組件樹:遵循“自頂而下,逐步求精”的原則,我們從組件的頂層開始,再一步步往下構(gòu)建組件樹;


    組件劃分(1)

    組件劃分(2)

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(二)】

  1. React.js 認(rèn)為所有的狀態(tài)都應(yīng)該由 React.js 的 state 控制,只要類似于 <input /><textarea /><select /> 這樣的輸入控件被設(shè)置了 value 值,那么它們的 value 值永遠(yuǎn)以被設(shè)置的 state 值為準(zhǔn)。 state 值不變,value 就不會(huì)變化;
  2. 類似于 <input /><textarea /><select /> 這些元素的 value 值被 React.js 所控制、渲染的組件,在 React.js 當(dāng)中被稱為受控組件(Controlled Component)。對于用戶可輸入的控件,一般都可以讓它們成為受控組件,這是 React.js 所推崇的做法
  3. CommentApp 組件將 CommentInputCommentList 組合起來,它是它們倆的父組件,可以充當(dāng)橋接兩個(gè)子組件的橋梁。所以當(dāng)用戶點(diǎn)擊發(fā)布按鈕的時(shí)候,我們就將 CommentInputstate 當(dāng)中最新的評(píng)論數(shù)據(jù)傳遞給父組件 CommentApp,然后讓父組件把這個(gè)數(shù)據(jù)傳遞給 CommentList 進(jìn)行渲染;
  4. 向父組件傳遞數(shù)據(jù):父組件 CommentApp 只需要通過 props 給子組件 CommentInput 傳入一個(gè)回調(diào)函數(shù)。當(dāng)用戶點(diǎn)擊發(fā)布按鈕的時(shí)候,CommentInput 調(diào)用 props 中的回調(diào)函數(shù)并且將 state 傳入該函數(shù)即可;

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(三)】

  1. 實(shí)現(xiàn)功能之前先理解、分析需求,劃分組件。并且掌握劃分組件的基本原則——可復(fù)用性、可維護(hù)性
  2. 受控組件的概念,React.js 中的 <input /><textarea /><select /> 等元素的 value 值如果是受到 React.js 的控制,那么就是受控組件;
  3. 組件之間使用 props 通過父元素傳遞數(shù)據(jù)的技巧:
    向父組件傳遞數(shù)據(jù):父組件 CommentApp 只需要通過 props 給子組件 CommentInput 傳入一個(gè)回調(diào)函數(shù)。當(dāng)用戶點(diǎn)擊發(fā)布按鈕的時(shí)候,CommentInput 調(diào)用 props 中的回調(diào)函數(shù)并且將 state 傳入該函數(shù)即可;

React.js 小書學(xué)習(xí) 之 【前端應(yīng)用狀態(tài)管理 — 狀態(tài)提升】

  1. 組件間數(shù)據(jù)共享:我們將組件之間共享的狀態(tài)交給組件最近的公共父節(jié)點(diǎn)保管,然后最近的公共父節(jié)點(diǎn)通過 props 把狀態(tài)(數(shù)據(jù))傳遞給子組件,這樣就可以在組件之間共享數(shù)據(jù)了;
  2. 當(dāng)某個(gè)狀態(tài)被多個(gè)組件依賴或者影響的時(shí)候,就把該狀態(tài)提升到這些組件的最近公共父組件中去管理,用 props 傳遞數(shù)據(jù)或者函數(shù)來管理這種依賴或著影響的行為;
  3. React.js 并沒有提供好的解決方案來管理這種組件之間的共享狀態(tài)。在實(shí)際項(xiàng)目當(dāng)中狀態(tài)提升并不是一個(gè)好的解決方案,所以需要引入 Redux 這樣的狀態(tài)管理工具來幫助我們來管理這種共享狀態(tài);

React.js 小書學(xué)習(xí) 之 【掛載階段的組件生命周期(一)】

  1. 組件的掛載(初始化組件 -> 掛載到頁面上的過程):React.js 將組件渲染,并且構(gòu)造 DOM 元素然后塞入頁面的過程;
  2. React.js 控制組件在頁面上掛載和刪除過程的幾個(gè)方法:
    1、componentWillMount:組件掛載開始之前,也就是在組件調(diào)用 render 方法之前調(diào)用;
    2、componentDidMount:組件掛載完成以后,也就是 DOM 元素已經(jīng)插入頁面后調(diào)用;
    3、componentWillUnmount:組件對應(yīng)的 DOM 元素從頁面中刪除之前調(diào)用;
    組件掛載和刪除過程方法(掛載階段生命周期及調(diào)用順序)

React.js 小書學(xué)習(xí) 之 【掛載階段的組件生命周期(二)】

  1. 把組件的 state 的初始化工作放在 constructor 里面去做;
  2. componentWillMount 進(jìn)行組件的啟動(dòng)工作,例如 Ajax 數(shù)據(jù)拉取、定時(shí)器的啟動(dòng);
  3. 有些組件的啟動(dòng)工作是依賴 DOM 的,例如動(dòng)畫的啟動(dòng),而 componentWillMount 的時(shí)候組件還沒掛載完成,所以沒法進(jìn)行這些啟動(dòng)工作,這時(shí)候就可以把這些操作放在 componentDidMount 當(dāng)中;
  4. 組件從頁面上銷毀的時(shí)候,有時(shí)候需要一些數(shù)據(jù)的清理,例如定時(shí)器的清理,就會(huì)放在 componentWillUnmount 里面去做;

React.js 小書學(xué)習(xí) 之 【更新階段的組件生命周期】

  1. 組件的掛載指的是將組件渲染并且構(gòu)造 DOM 元素然后插入頁面的過程。這是一個(gè)從無到有的過程,React.js 提供一些生命周期函數(shù)可以給我們在這個(gè)過程中做一些操作;
  2. 組件更新階段:說白了就是 setState 導(dǎo)致 React.js 重新渲染組件并且把組件的變化應(yīng)用到 DOM 元素上的過程,這是一個(gè)組件變化的過程
  3. 更新階段的組件生命周期
    1、shouldComponentUpdate(nextProps, nextState):你可以通過這個(gè)方法控制組件是否重新渲染如果返回 false 組件就不會(huì)重新渲染。這個(gè)生命周期在 React.js 性能優(yōu)化上非常有用;
    2、componentWillReceiveProps(nextProps):組件從父組件接收到新的 props 之前調(diào)用;
    3、componentWillUpdate():組件開始重新渲染之前調(diào)用;
    4、componentDidUpdate():組件重新渲染并且把更改變更到真實(shí)的 DOM 以后調(diào)用;

React.js 小書學(xué)習(xí) 之 【ref 和 React.js 中的 DOM 操作】

  1. 在 React.js 當(dāng)中可以直接通過 setState 的方式重新渲染組件,渲染的時(shí)候可以把新的 props 傳遞給子組件,從而達(dá)到頁面更新的效果;

  2. React.js 這種重新渲染的機(jī)制幫助我們免除了絕大部分的 DOM 更新操作,也讓類似于 jQuery 這種以封裝 DOM 操作為主的第三方的庫從我們的開發(fā)工具鏈中刪除;

  3. JSX 元素加上 ref 屬性:獲取掛載完成后的當(dāng)前 DOM 節(jié)點(diǎn)對象, ref 屬性值是一個(gè)函數(shù),接受一個(gè)參數(shù)(當(dāng)前 DOM 節(jié)點(diǎn)對象),在函數(shù)中我們把這個(gè)參數(shù)(DOM 元素)設(shè)置為組件實(shí)例的一個(gè)屬性,這樣以后我們就可以通過 this.input 屬性獲取到這個(gè) DOM 元素了,再配合 componentDidMount 生命周期函數(shù)使用這個(gè) DOM 元素,并且調(diào)用類似 this.input.focus() 的 DOM API,進(jìn)行相關(guān)的DOM操作;
    注:原則上,能不用 ref 就不用

     import React, { Component } from 'react'
     import ReactDOM from 'react-dom'
     import './index.css'
    
     class AutoFocusInput extends Component {
         componentDidMount () {
             // DOM 節(jié)點(diǎn)加載完,才能調(diào)用 DOM API,
             // 所以放在 componentDidMount 生命周期里
             this.input.focus()
         }
    
         render () {
             return (
                 <div>
                     <input ref={(input) => this.input = input} />
                     {/* 組件標(biāo)簽也可以加上 ref
                             獲取到的是這個(gè) Clock 組件在 React.js 內(nèi)部初始化的實(shí)例
                             但這并不是什么常用的做法,而且也并不建議這么做 */}
                     {/* <Clock ref={(clock) => this.clock = clock} /> */}
                 </div>
             )
         }
     }
    
     ReactDOM.render(
         <AutoFocusInput />,
         document.getElementById('root')
     )
    

React.js 小書學(xué)習(xí) 之 【props.children 和容器類組件】

  1. 如果組件標(biāo)簽也能像普通的 HTML 標(biāo)簽?zāi)菢泳帉憙?nèi)嵌的結(jié)構(gòu),那么就方便很多了。實(shí)際上,React.js 默認(rèn)就支持這種寫法,所有嵌套在組件中的 JSX 結(jié)構(gòu)都可以在組件內(nèi)部通過 props.children (是一個(gè)數(shù)組)獲取到;

React.js 小書學(xué)習(xí) 之 【dangerouslySetHTML 和 style 屬性】

  1. 出于安全考慮的原因(XSS 攻擊),在 React.js 當(dāng)中所有的表達(dá)式插入的內(nèi)容都會(huì)被自動(dòng)轉(zhuǎn)義成文本形式,就相當(dāng)于 jQuery 里面的 text(…) 函數(shù)一樣,任何的 HTML 格式都會(huì)被轉(zhuǎn)義成其對應(yīng)的文本形式渲染,也就是說,表達(dá)式插入的內(nèi)容中的HTML結(jié)構(gòu)渲染是會(huì)被原樣輸出,不會(huì)采用HTML語法格式渲染;

  2. React.js 提供了一個(gè)屬性 dangerouslySetInnerHTML,可以讓我們設(shè)置動(dòng)態(tài)設(shè)置元素的 innerHTML;

     import React, { Component } from 'react'
     import ReactDOM from 'react-dom'
     import './index.css'
    
     class Editor extends Component {
       constructor() {
         super()
         this.state = {
           content: '<h1>React.js 小書</h1>'
         }
       }
    
       render () {
         return (
           <div>
             {/* 正確 動(dòng)態(tài)設(shè)置元素的 innerHTML */}
             <div className='editor-wrapper' dangerouslySetInnerHTML={{__html: this.state.content}} />
             
             {/* 錯(cuò)誤 動(dòng)態(tài)設(shè)置元素的 innerHTML */}
             <div className='editor-wrapper'>
               {this.state.content}
             </div>
           </div>
         )
       }
     }
    
     ReactDOM.render(
       <Editor />,
       document.getElementById('root')
     )
    
  3. 因?yàn)樵O(shè)置 innerHTML 可能會(huì)導(dǎo)致跨站腳本攻擊(XSS),所以 React.js 團(tuán)隊(duì)認(rèn)為把事情搞復(fù)雜可以防止(警示)大家濫用這個(gè)屬性, dangerouslySetInnerHTML 這個(gè)屬性不必要的情況就不要使用;

  4. style屬性style 接受一個(gè)對象,這個(gè)對象里面是這個(gè)元素的 CSS 屬性鍵值對,原來 CSS 屬性中帶 - 的元素都必須要去掉 - 換成駝峰命名,如 font-size 換成 fontSizetext-align 換成 textAlign

     <h1 style={{fontSize: '12px', color: this.state.color}}>React.js 小書</h1>
    

React.js 小書學(xué)習(xí) 之 【PropTypes 和組件參數(shù)驗(yàn)證】

  1. React.js 就提供了一種機(jī)制,讓你可以給組件的配置參數(shù)加上類型驗(yàn)證,如果傳進(jìn)來的配置參數(shù)類型不符合要求,便會(huì)強(qiáng)制報(bào)錯(cuò);

  2. 組件參數(shù)驗(yàn)證 依賴于 React 提供的第三方庫 prop-types,安裝命令如下:
    npm: npm install --save prop-types
    yarn: yarn add prop-types

  3. 使用如下:

     import React, { Component } from 'react';
     import PropTypes from 'prop-types'; // 引入?yún)?shù)校驗(yàn)依賴
    
     class Comment extends Component {
       // 定義組件類 參數(shù)類型屬性
       static propTypes = {
         // 定義對應(yīng)參數(shù)類型: object-對象; isRequired-必須傳值
         // 必傳 對象類型 的參數(shù)
         comment: PropTypes.object.isRequired
       }
    
       render () {
         const { comment } = this.props
         return (
           <div className='comment'>
             <div className='comment-user'>
               <span>{comment.username} </span>:
             </div>
             <p>{comment.content}</p>
           </div>
         )
       }
     }
    
  4. React.js 提供的 PropTypes 提供了一系列的數(shù)據(jù)類型可以用來配置組件的參數(shù):

    PropTypes 的數(shù)據(jù)類型

  5. 通過 PropTypes 給組件的參數(shù)做類型限制,可以在幫助我們迅速定位錯(cuò)誤,這在構(gòu)建大型應(yīng)用程序的時(shí)候特別有用;另外,給組件加上 propTypes,也讓組件的開發(fā)、使用更加規(guī)范清晰;

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(四)】

  1. 數(shù)據(jù)加載操作等不依賴 DOM 操作的組件啟動(dòng)的操作都可以放在 componentWillMount 中進(jìn)行;
  2. React 小書 小貼士(1):組件的私有方法都用 _ 開頭,所有事件監(jiān)聽的方法都用 handle 開頭。把事件監(jiān)聽方法傳給組件的時(shí)候,屬性名用 on 開頭;
  3. React 小書 小貼士(2):組件的內(nèi)容編寫順序(推薦)
    1、static 開頭的組件類屬性,如 defaultPropspropTypes
    2、構(gòu)造函數(shù),constructor
    3、getter/setter 方法;
    4、組件生命周期;
    5、_ 開頭的私有方法;
    6、事件監(jiān)聽方法,handle*
    7、render* 開頭的方法,有時(shí)候 render() 方法里面的內(nèi)容會(huì)分開到不同函數(shù)里面進(jìn)行,這些函數(shù)都以 render* 開頭;
    8、render() 方法;

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(五)】

暫無

React.js 小書學(xué)習(xí) 之 【實(shí)戰(zhàn)分析:評(píng)論功能(六)】

  1. dangerouslySetInnerHTML 屬性:動(dòng)態(tài)設(shè)置元素的 innerHTML,該屬性能不用就不用,易造成 XSS 跨站腳本攻擊漏洞,如果用的話,也應(yīng)該對相應(yīng)的 HTML 字符進(jìn)行轉(zhuǎn)義處理,如下:

     /* ``符號(hào) 包含的內(nèi)容轉(zhuǎn) <code></code> 處理 */
     <p dangerouslySetInnerHTML={{
         __html: this._getProcessedContent(this.props.comment.content)
     }} />
    
     /**
      * ``符號(hào) 包含的內(nèi)容轉(zhuǎn) <code></code> 處理
      */
     _getProcessedContent (content) {
         return content
             .replace(/&/g, "&amp;")
             .replace(/</g, "&lt;")
             .replace(/>/g, "&gt;")
             .replace(/"/g, "&quot;")
             .replace(/'/g, "&#039;")
             .replace(/`([\S\s]+?)`/g, '<code>$1</code>');
     }
    

React.js 小書學(xué)習(xí) 之 【高階組件(Higher-Order Components)】

  1. 高階組件:高階組件是一個(gè)函數(shù)(而不是組件),它接收一個(gè)子組件作為參數(shù),返回一個(gè)新組件。新組件會(huì)使用傳入的組件作為子組件;

     const NewComponent = higherOrderComponent(OldComponent);
    
  2. 高階組件的作用其實(shí)不言而喻,其實(shí)就是為了組件之間的代碼復(fù)用。組件可能有著某些相同的邏輯,把這些邏輯抽離出來,放到高階組件中進(jìn)行復(fù)用。高階組件內(nèi)部的包裝組件和被包裝組件之間通過 props 傳遞數(shù)據(jù)

  3. 用法示例:

     // 第一個(gè)文件  定義高階組件: 高階組件就是一個(gè)函數(shù),接收一個(gè)子組件作為參數(shù),返回一個(gè)新組件
     import React, { Component } from 'react'
     export default (WrappedComponent, name) => {
         class NewComponent extends Component {
             constructor () {
                 super()
                 this.state = { data: null }
             }
    
             componentWillMount () {
                 let data = localStorage.getItem(name)
                 this.setState({ data })
             }
    
             render () {
                 return <WrappedComponent data={this.state.data} />
             }
         }
         return NewComponent
     }
    
    
     // 第二個(gè)文件  使用高階組件(調(diào)用高階組件函數(shù)): 創(chuàng)建高階組件處理后的新組件并導(dǎo)出
     import wrapWithLoadData from './wrapWithLoadData' // 從 ./wrapWithLoadData文件 引入高階組件
     class InputWithUserName extends Component {
         render () {
             return <input value={this.props.data} />
         }
     }
     InputWithUserName = wrapWithLoadData(InputWithUserName, 'username')
     export default InputWithUserName
    
    
     // 第三個(gè)文件  使用被高階組件加工過的導(dǎo)出后的新組件
     import InputWithUserName from './InputWithUserName' // 從 ./InputWithUserName文件 引入 InputWithUserName 組件
     class Index extends Component {
         render () {
             return (
                 <div>
                     用戶名:<InputWithUserName />
                 </div>
             )
         }
     }
    
  4. 多層高階組件數(shù)據(jù)流向,如圖:
    要求:需要先從 LocalStorage 中加載數(shù)據(jù),再用這個(gè)數(shù)據(jù)去服務(wù)器取數(shù)據(jù)


    多層高階組件數(shù)據(jù)流向

React.js 小書學(xué)習(xí) 之 【React.js 的 context】

  1. 除非你覺得自己的 React.js 水平已經(jīng)比較爐火純青了,否則你永遠(yuǎn)不要使用 context ,只需要用好這些第三方的應(yīng)用狀態(tài)管理庫就行了,如: Redux 。就像你學(xué) JavaScript 的時(shí)候,總是會(huì)被提醒不要用全局變量一樣,React.js 的 context 其實(shí)就像是組件樹上某顆子樹的全局變量;
  2. React.js 的 context:某個(gè)組件只要往自己的 context 里面放了某些狀態(tài),這個(gè)組件之下的所有子組件都直接訪問這個(gè)狀態(tài)而不需要通過中間組件的傳遞。一個(gè)組件的 context 只有它的子組件能夠訪問,它的父組件是不能訪問到的,你可以理解每個(gè)組件的 context 就是瀑布的源頭,只能往下流不能往上飛;
  3. React小書總結(jié)(提示注意點(diǎn)):
    1、一個(gè)組件可以通過 getChildContext 方法返回一個(gè)對象,這個(gè)對象就是子樹的 context,提供 context 的組件必須提供 childContextTypes 作為 context 的聲明和驗(yàn)證。
    2、如果一個(gè)組件設(shè)置了 context,那么它的子組件都可以直接訪問到里面的內(nèi)容,它就像這個(gè)組件為根的子樹的全局變量。任意深度的子組件都可以通過 contextTypes 來聲明你想要的 context 里面的哪些狀態(tài),然后可以通過 this.context 訪問到那些狀態(tài)。
    3、context 打破了組件和組件之間通過 props 傳遞數(shù)據(jù)的規(guī)范,極大地增強(qiáng)了組件之間的耦合性。而且,就如全局變量一樣,context 里面的數(shù)據(jù)能被隨意接觸就能被隨意修改,每個(gè)組件都能夠改 context 里面的內(nèi)容會(huì)導(dǎo)致程序的運(yùn)行不可預(yù)料。

React.js 小書學(xué)習(xí) 之 【動(dòng)手實(shí)現(xiàn) Redux(一):優(yōu)雅地修改共享狀態(tài)】

  1. Redux 和 React-redux 并不是同一個(gè)東西。Redux 是一種架構(gòu)模式(Flux 架構(gòu)的一種變種),它不關(guān)注你到底用什么庫,你可以把它應(yīng)用到 React 和 Vue,甚至跟 jQuery 結(jié)合都沒有問題。而 React-redux 就是把 Redux 這種架構(gòu)模式和 React.js 結(jié)合起來的一個(gè)庫,就是 Redux 架構(gòu)在 React.js 中的體現(xiàn);
  2. 定義 dispatch 中間處理函數(shù),它專門負(fù)責(zé)數(shù)據(jù)的修改,所有對數(shù)據(jù)的操作必須通過 dispatch 函數(shù)。它接受一個(gè)參數(shù) action,這個(gè) action 是一個(gè)普通的 JavaScript 對象,里面必須包含一個(gè) type 字段來聲明你到底想干什么。dispatchswtich 里面會(huì)識(shí)別這個(gè) type 字段,能夠識(shí)別出來的操作才會(huì)執(zhí)行對共享狀態(tài) appState 的修改;

React.js 小書學(xué)習(xí) 之 【動(dòng)手實(shí)現(xiàn) Redux(二):抽離 store 和監(jiān)控?cái)?shù)據(jù)變化】

  1. 針對每個(gè)不同的 App,我們可以給 createStore 傳入初始的共享狀態(tài)數(shù)據(jù) appState 和一個(gè)描述數(shù)據(jù)變化的函數(shù) stateChanger,然后生成一個(gè) store。需要修改數(shù)據(jù)的時(shí)候通過 store.dispatch,需要獲取數(shù)據(jù)的時(shí)候通過 store.getState

  2. 通用的 createStore,它可以產(chǎn)生一種我們新定義的數(shù)據(jù)類型 store,通過 store.getState 我們獲取共享狀態(tài),而且我們約定只能通過 store.dispatch 修改共享狀態(tài)。store 也允許我們通過 store.subscribe 監(jiān)聽數(shù)據(jù)數(shù)據(jù)狀態(tài)被修改了,并且進(jìn)行后續(xù)的例如重新渲染頁面的操作;

  3. 本節(jié)完整代碼示例如下:

     function createStore(state, stateChanger) {
         const listeners = []
         const subscribe = (listener) => listeners.push(listener)
         const getState = () => state
         const dispatch = (action) => {
             stateChanger(state, action)
             listeners.forEach((listener) => listener())
         }
         return { getState, dispatch, subscribe }
     }
    
     function renderApp(appState) {
         renderTitle(appState.title)
         renderContent(appState.content)
     }
    
     function renderTitle(title) {
         const titleDOM = document.getElementById('title')
         titleDOM.innerHTML = title.text
         titleDOM.style.color = title.color
     }
    
     function renderContent(content) {
         const contentDOM = document.getElementById('content')
         contentDOM.innerHTML = content.text
         contentDOM.style.color = content.color
     }
    
     let appState = {
         title: {
             text: 'React.js 小書',
             color: 'red',
         },
         content: {
             text: 'React.js 小書內(nèi)容',
             color: 'blue'
         }
     }
    
     function stateChanger(state, action) {
         switch (action.type) {
             case 'UPDATE_TITLE_TEXT':
                 state.title.text = action.text
                 break
             case 'UPDATE_TITLE_COLOR':
                 state.title.color = action.color
                 break
             default:
                 break
         }
     }
    
     const store = createStore(appState, stateChanger)
     store.subscribe(() => renderApp(store.getState())) // 監(jiān)聽數(shù)據(jù)變化
    
     renderApp(store.getState()) // 首次渲染頁面
     store.dispatch({ // 修改標(biāo)題文本
         type: 'UPDATE_TITLE_TEXT',
         text: '《React.js 小書》'
     })
     store.dispatch({ // 修改標(biāo)題顏色
         type: 'UPDATE_TITLE_COLOR',
         color: 'blue'
     })
    

React.js 小書學(xué)習(xí) 之 【動(dòng)手實(shí)現(xiàn) Redux(三):純函數(shù)(Pure Function)簡介】

  1. 純函數(shù)(Pure Function): 一個(gè)函數(shù)的返回結(jié)果只依賴于它的參數(shù),并且在執(zhí)行過程里面沒有副作用,我們就把這個(gè)函數(shù)叫做純函數(shù);
  2. 一個(gè)函數(shù)執(zhí)行過程產(chǎn)生了外部可觀察的變化那么就說這個(gè)函數(shù)是有副作用的;
  3. 外部可觀察的變化:除了修改外部的變量,一個(gè)函數(shù)在執(zhí)行過程中還有很多方式產(chǎn)生外部可觀察的變化,比如說調(diào)用 DOM API 修改頁面,或者你發(fā)送了 Ajax 請求,還有調(diào)用 window.reload 刷新瀏覽器,甚至是 console.log 往控制臺(tái)打印數(shù)據(jù)也是副作用;
  4. 純函數(shù)很嚴(yán)格,也就是說你幾乎除了計(jì)算數(shù)據(jù)以外什么都不能干,計(jì)算的時(shí)候還不能依賴除了函數(shù)參數(shù)以外的數(shù)據(jù);

React.js 小書學(xué)習(xí) 之 【動(dòng)手實(shí)現(xiàn) Redux(四):共享結(jié)構(gòu)的對象提高性能】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)是面向過程的,函數(shù)的調(diào)用不需要主體,而方法是屬于對象的,調(diào)用方法需要一個(gè)主體-即對象。 npm install...
    Gukson666閱讀 479評(píng)論 0 3
  • 1、什么是react React.js 是一個(gè)幫助你構(gòu)建頁面 UI 的庫。React.js 將幫助我們將界面分成了...
    谷子多閱讀 2,566評(píng)論 1 13
  • react 基本概念解析 react 的組件聲明周期 react 高階組件,context, redux 等高級(jí)...
    南航閱讀 1,084評(píng)論 0 1
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,099評(píng)論 2 35
  • 遙望朝陽日漸升,說是朝陽無限美。 眾人皆是贊朝陽,我卻獨(dú)愛夕陽美。 朝陽雖說好寓意,夕陽西下意鏡好。 有朝陽升夕陽...
    蘭公主閱讀 488評(píng)論 0 1