React知識點總結

2021-02-18 字節愛好者

下面總結一下知識點,便於查看:

1.事件

2.表單

3.setState

4.生命周期

5.函數組件

6.非受控組件

7.Portals

8.context

9.異步組件

10.性能優化

11.高階組件HOC

12.Render Props




事件

1.使用bind

import React from 'react'
class EventDemo extends React.Component { constructor(props) { super(props) this.state = { name: 'zhangsan', }
// 修改方法的 this 指向 this.clickHandler1 = this.clickHandler1.bind(this) } render() { // // this - 使用 bind return <p onClick={this.clickHandler1}> {this.state.name} </p> } clickHandler1() { console.log('this....', this) // this 默認是 undefined this.setState({ name: 'lisi' }) }}
export default EventDemo

2.使用靜態方法

// this - 使用靜態方法return <p onClick={this.clickHandler2}>clickHandler2 {this.state.name}</p>
// 靜態方法,this 指向當前實例clickHandler2 = () => { this.setState({ name: 'lisi' })}

3.event

<a href="https://baidu.com/" onClick={this.clickHandler3}>click me</a>
// 獲取 eventclickHandler3 = (event) => { event.preventDefault() // 阻止默認行為 event.stopPropagation() // 阻止冒泡 console.log('target', event.target) // 指向當前元素,即當前元素觸發 console.log('current target', event.currentTarget) // 指向當前元素,假象!!!
// 注意,event 其實是 React 封裝的。可以看 __proto__.constructor 是 SyntheticEvent 組合事件 console.log('event', event) // 不是原生的 Event ,原生的是 MouseEvent console.log('event.__proto__.constructor', event.__proto__.constructor)
// 原生 event 如下。其 __proto__.constructor 是 MouseEvent console.log('nativeEvent', event.nativeEvent) console.log('nativeEvent target', event.nativeEvent.target) // 指向當前元素,即當前元素觸發 console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!!
// 1. event 是 SyntheticEvent ,模擬出來 DOM 事件所有能力 // 2. event.nativeEvent 是原生事件對象 // 3. 所有的事件,都被掛載到 document 上 // 4. 和 DOM 事件不一樣,和 Vue 事件也不一樣}

結果如下:

表單

受控組件:通過change事件來改變state

import React from 'react'
class FormDemo extends React.Component { constructor(props) { super(props) this.state = {            name: 'curry', info: '個人信息', city: 'beijing', flag: true, gender: 'male' } } render() {
// // 受控組件 // return <div> // <p>{this.state.name}</p> // <label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */} // <input id="inputName" value={this.state.name} onChange={this.onInputChange}/> // </div>
// textarea - 使用 value return <div> <textarea value={this.state.info} onChange={this.onTextareaChange}/> <p>{this.state.info}</p> </div>
// // select - 使用 value return <div> <select value={this.state.city} onChange={this.onSelectChange}> <option value="beijing">北京</option> <option value="shanghai">上海</option> <option value="shenzhen">深圳</option> </select> <p>{this.state.city}</p> </div>
// // checkbox return <div> <input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/> <p>{this.state.flag.toString()}</p> </div>
// // radio return <div> male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/> female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/> <p>{this.state.gender}</p> </div> } onInputChange = (e) => { this.setState({ name: e.target.value }) } onTextareaChange = (e) => { this.setState({ info: e.target.value }) } onSelectChange = (e) => { this.setState({ city: e.target.value }) } onCheckboxChange = () => { this.setState({ flag: !this.state.flag }) } onRadioChange = (e) => { this.setState({ gender: e.target.value }) }}
export default FormDemo

setState

1.不可變值

2.可能是異步更新

3.可能會被合併

不可變值:

import React from 'react'
class StateDemo extends React.Component { constructor(props) { super(props)
// 第一,state 要在構造函數中定義 this.state = { count: 0 } } render() { return <div> <p>{this.state.count}</p> <button onClick={this.increase}>累加</button> </div> } increase = () => { // 第二,不要直接修改 state ,使用不可變值 --- // this.state.count++ // 錯誤 this.setState({ count: this.state.count + 1 // SCU }) // 操作數組、對象的的常用形式 // 不可變值(函數式編程,純函數) - 數組 const list5Copy = this.state.list5.slice() list5Copy.splice(2, 0, 'a') // 中間插入/刪除 this.setState({ list1: this.state.list1.concat(100), // 追加 list2: [...this.state.list2, 100], // 追加 list3: this.state.list3.slice(0, 3), // 截取 list4: this.state.list4.filter(item => item > 100), // 篩選 list5: list5Copy // 其他操作 }) // 注意,不能直接對 this.state.list 進行 push pop splice 等,這樣違反不可變值
// 不可變值 - 對象 this.setState({ obj1: Object.assign({}, this.state.obj1, {a: 100}), obj2: {...this.state.obj2, a: 100} }) // 注意,不能直接對 this.state.obj 進行屬性設置,這樣違反不可變值 }}
export default StateDemo

可能是異步更新:

this.setState({    count: this.state.count + 1}, () => {    console.log('count by callback', this.state.count) // 回調函數中可以拿到最新的 state})console.log('count', this.state.count) // 異步的,拿不到最新值

列印如下:


setTimeout 中 setState 是同步的:

// setTimeout 中 setState 是同步的setTimeout(() => {    this.setState({        count: this.state.count + 1    })    console.log('count in setTimeout', this.state.count)}, 0)

列印如下:


自己定義的 DOM 事件,setState 是同步的

 bodyClickHandler = () => {    this.setState({        count: this.state.count + 1    })    console.log('count in body event', this.state.count)}componentDidMount() {    // 自己定義的 DOM 事件,setState 是同步的    document.body.addEventListener('click', this.bodyClickHandler)}


列印如下:

可能會被合併:

傳入對象,會被合併(類似 Object.assign )

 // 傳入對象,會被合併(類似 Object.assign )。執行結果只一次 +1this.setState({    count: this.state.count + 1})this.setState({    count: this.state.count + 1})this.setState({    count: this.state.count + 1})

傳入函數,不會被合併。

  // 傳入函數,不會被合併。執行結果是 +3  this.setState((prevState, props) => {      return {          count: prevState.count + 1      }  })  this.setState((prevState, props) => {      return {          count: prevState.count + 1      }  })  this.setState((prevState, props) => {      return {          count: prevState.count + 1      }  })

生命周期:

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

React高級特性:
1.函數組件

2.非受控組件

3.Portals

4.context

5.異步組件

6.性能優化

7.高階組件HOC

8.Render Props

函數組件:

1.純函數,輸入props,輸出jsx

2.沒有實例,沒有生命周期,沒有state


非受控組件:

1.ref

2.defaultValue defaultChexked

3.手動操作dom元素


ref:

第一步:創建ref

第二步:綁定到dom元素

第三步:通過this.nameInputRef.current 獲取dom

第四步:操作dom

使用場景:必須手動操作dom,不能使用state。如上傳文件。

import React from 'react'
class App extends React.Component { constructor(props) { super(props) this.state = { name: 'curry', flag: true, } // 第一步:創建ref this.nameInputRef = React.createRef() // 創建 ref } render() { return <div> {/* 使用 defaultValue 而不是 value ,使用 ref */} // 第二步:綁定到dom元素 <input defaultValue={this.state.name} ref={this.nameInputRef}/> {/* state 並不會隨著改變 */} <span>state.name: {this.state.name}</span> <br/> <button onClick={this.alertName}>alert name</button> </div> } alertName = () => { // 第三步:通過this.nameInputRef.current 獲取dom const elem = this.nameInputRef.current // 通過 ref 獲取 DOM 節點 // 第四步:操作dom alert(elem.value) // 不是 this.state.name }}
export default App

受控組件 vs 非受控組件:

1.優先使用受控組件,符合react設計原則

2.必須操作dom,再使用非受控組件

Portals

作用:讓組件渲染到父組件外


先看下組件正常渲染

import React from 'react'import ReactDOM from 'react-dom'import './style.css'
class App extends React.Component { constructor(props) { super(props) this.state = { } } render() { // // 正常渲染 return <div className="modal"> {this.props.children} {/* vue slot */} </div> }}
export default App

.modal {    position: fixed;    width: 300px;    height: 100px;    top: 100px;    left: 50%;    margin-left: -150px;    background-color: #000;    /* opacity: .2; */    color: #fff;    text-align: center;}

如下:modal渲染到了body裡面。


使用Portals將modal渲染到body第一層。

import React from 'react'import ReactDOM from 'react-dom'import './style.css'
class App extends React.Component { constructor(props) { super(props) this.state = { } } render() { // 使用 Portals 渲染到 body 上。 // fixed 元素要放在 body 上,有更好的瀏覽器兼容性。 return ReactDOM.createPortal( <div className="modal">{this.props.children}</div>, document.body // DOM 節點 ) }}
export default App


如下:modal就在body第一層了。


Portals使用場景:

1.overflow:hidden

2.z-index值太小

3.fixed需要放在body第一層


context:

適用公共信息傳遞給每個組件


第一步:創建 Context 填入默認值(任何一個 js 變量)

const ThemeContext = React.createContext('light')

第二步:將需要共享的數據放到ThemeContext.Provider裡面的value屬性,同時將需要消費共享數據的組件放到ThemeContext.Provider裡面。

直接看下代碼:

<ThemeContext.Provider value={this.state.theme}>    <Toolbar />    <hr/>    <button onClick={this.changeTheme}>change theme</button></ThemeContext.Provider>

第三步:在消費的組件中獲取並使用

ThemedButton.contextType = ThemeContext // 指定 contextType 讀取當前的 theme context。// 底層組件 - class 組件class ThemedButton extends React.Component {    // 指定 contextType 讀取當前的 theme context。    // static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContext    render() {        const theme = this.context // React 會往上找到最近的 theme Provider,然後使用它的值。        return <div>            <p>button's theme is {theme}</p>        </div>    }}

還可以使用ThemeContext.Consumer來消費共享數據

// 底層組件 - 函數是組件function ThemeLink (props) {    // const theme = this.context // 會報錯。函數式組件沒有實例,即沒有 this
// 函數式組件可以使用 Consumer return <ThemeContext.Consumer> { value => <p>link's theme is {value}</p> } </ThemeContext.Consumer>}

全部代碼如下:

import React from 'react'
// 創建 Context 填入默認值(任何一個 js 變量)const ThemeContext = React.createContext('light')
// 底層組件 - 函數是組件function ThemeLink (props) { // const theme = this.context // 會報錯。函數式組件沒有實例,即沒有 this
// 函數式組件可以使用 Consumer return <ThemeContext.Consumer> { value => <p>link's theme is {value}</p> } </ThemeContext.Consumer>}
// 底層組件 - class 組件class ThemedButton extends React.Component { // 指定 contextType 讀取當前的 theme context。 // static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContext render() { const theme = this.context // React 會往上找到最近的 theme Provider,然後使用它的值。 return <div> <p>button's theme is {theme}</p> </div> }}ThemedButton.contextType = ThemeContext // 指定 contextType 讀取當前的 theme context。
// 中間的組件再也不必指明往下傳遞 theme 了。function Toolbar(props) { return ( <div> <ThemedButton /> <ThemeLink /> </div> )}
class App extends React.Component { constructor(props) { super(props) this.state = { theme: 'light' } } render() { return <ThemeContext.Provider value={this.state.theme}> <Toolbar /> <hr/> <button onClick={this.changeTheme}>change theme</button> </ThemeContext.Provider> } changeTheme = () => { this.setState({ theme: this.state.theme === 'light' ? 'dark' : 'light' }) }}
export default App

異步組件:
1.import()

2.React.lazy

3.React.Suspense

import React from 'react'
const ContextDemo = React.lazy(() => import('./ContextDemo'))
class App extends React.Component { constructor(props) { super(props) } render() { return <div> <p>引入一個動態組件</p> <hr /> <React.Suspense fallback={<div>Loading...</div>}> <ContextDemo/> </React.Suspense> </div> }}
export default App

性能優化:

1.scu:shouldComponentUpdate

2.PureComponent和React.memo

3.不可變值immutable.js

scu:

默認返回true

shouldComponentUpdate(nextProps, nextState) {    if (nextState.count !== this.state.count) {        return true // 可以渲染    }    return false // 不重複渲染}

父組件更新,子組件也會更新。這時需要scu。


PureComponent:SCU中實現了淺比較, Class組件

React.memo:函數組件

高階組件

接收一個組件,返回一個新組件

import React from 'react'
// 高階組件const withMouse = (Component) => { class withMouseComponent extends React.Component { constructor(props) { super(props) this.state = { x: 0, y: 0 } }
handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }) }
render() { return ( <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}> {/* 1. 透傳所有 props 2. 增加 mouse 屬性 */} <Component {...this.props} mouse={this.state}/> </div> ) } } return withMouseComponent}
const App = (props) => { const a = props.a const { x, y } = props.mouse // 接收 mouse 屬性 return ( <div style={{ height: '500px' }}> <h1>The mouse position is ({x}, {y})</h1> <p>{a}</p> </div> )}
export default withMouse(App) // 返回高階函數

Render props

import React from 'react'import PropTypes from 'prop-types'
class Mouse extends React.Component { constructor(props) { super(props) this.state = { x: 0, y: 0 } }
handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY }) }
render() { return ( <div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}> {/* 將當前 state 作為 props ,傳遞給 render (render 是一個函數組件) */} {this.props.render(this.state)} </div> ) }}Mouse.propTypes = { render: PropTypes.func.isRequired // 必須接收一個 render 屬性,而且是函數}
const App = (props) => ( <div style={{ height: '500px' }}> <p>{props.a}</p> <Mouse render={ /* render 是一個函數組件 */ ({ x, y }) => <h1>The mouse position is ({x}, {y})</h1> }/>
</div>)
/** * 即,定義了 Mouse 組件,只有獲取 x y 的能力。 * 至於 Mouse 組件如何渲染,App 說了算,通過 render prop 的方式告訴 Mouse 。 */
export default App

相關焦點

  • 關於react結合redux使用,或許你還應該掌握這些
    最近小編委託組內小哥又給自己梳理了一遍react結合redux使用的知識點(因為懶,翻文檔不如白嫖來的開心呀),主要涉及使用的注意事項和使用流程,涉及的中間件以及如何處理異步數據等。完後,小編覺得有必要對這次的知識點做一個系統的整理,造(wu)福(ren)大(zi)眾(di)。
  • 【實戰總結篇】寫React Hooks前必讀
    必須完整閱讀一次React Hooks官方文檔英文文檔:https://reactjs.org/docs/hooks-intro.html中文文檔:https://zh-hans.reactjs.org/docs/hooks-intro.html其中重點必看hooks: useState、useReducer、useEffect、useCallback
  • React Status 中文周刊 #21 - 2020 年 React 大事記回顧
    原文連結:https://www.robinwieruch.de/react-librariesRobin Wieruch2.  5 個使用 Hook 編寫組件的常見錯誤 — 他人總結的經驗教訓一直備受青睞,而本文恰恰是這樣一篇文章 - 有關組件創建。
  • 30 分鐘精通 React 新特性——React Hooks
    如果你也對react感興趣,或者正在使用react進行項目開發,答應我,請一定抽出至少30分鐘的時間來閱讀本文好嗎?所有你需要了解的React Hooks的知識點,本文都涉及到了,相信完整讀完後你一定會有所收穫。
  • React + Redux + React-router 全家桶
    web端開發需要搭配React-dom使用import React from 'react';import ReactDOM from 'react-dom';const App = () => (  <div>      <
  • react腳手架create-react-app入門
    記得關注,每天都在分享不同知識不管是哪個前端框架都支持快速開發,通過腳手架可以讓咱們更便捷的構建項目,無需考慮搭建環境問題,今天來聊聊create-react-app腳手架安裝腳手架>npm install -g create-react-app創建項目create-react-app myapp # myapp是項目的名稱,這樣就會在當前目錄生成一個myapp的項目
  • 【前端技術】react渲染 - 流程概述
    實際上jsx 是來源於一個前端框架 react。在react中除了我們了解的jsx,那麼jsx在react的渲染過程是哪個環節生效,以及渲染過程經歷了哪些步驟。本文會基於這些點進行概述。1.本文的react.render樹狀圖.xmind,此為作者查看/調試react的渲染源碼時做的結構筆記。
  • React系列教程
    2.腳手架的介紹3.認識React的腳手架 - create-react-app4.腳手架的環境的下載及使用5.腳手架內部的基本構成介紹6.使用腳手架製作圖片展示組件 第十三講:React的動畫1.React動畫的基本使用2.React的動畫插件 - react-transition-group
  • React-Redux 使用 Hooks
    快速搭建 redux 環境    create-react-app redux-app    yarn  add react-redux reduxTips: 確保 react-redux 版本 在 v7.1.0 以上
  • React Hook 入門教程
    ,是學習 react 的一大大門檻,首先你得非常理解 JS 當中的 this 的工作方式,不然你怎麼綁定事件可能都是一個問題。Dan 總結 class 組件有三個不好的地方:業務邏輯分散在組件的各個方法之中,導致重複邏輯或關聯邏輯。組件類引入了複雜的編程模式,比如 render props 和高階組件。從概念上講,React 組件一直更像是函數。
  • React Native 開發日常、常見問題總結及解決
    方法:可以關注 阿里 相關的 技術公眾號,你能知道目前 熱門技術及乾貨;個人感覺前沿技術基本在 阿里系;跟著大公司的步伐學習不會錯、不會脫軌連結:Flutter 學習姿勢可點擊之前文章 一星期從入門到實際開發經驗分享及總結
  • 30 分鐘精通 React 今年最勁爆的新特性 —— React Hooks
    如果你也對react感興趣,或者正在使用react進行項目開發,答應我,請一定抽出至少30分鐘的時間來閱讀本文好嗎?所有你需要了解的React Hooks的知識點,本文都涉及到了,相信完整讀完後你一定會有所收穫。
  • ReactNative學習資源大匯集
    react-native 官方api文檔 http://facebook.github.io/react-native/docs/getting-started.htmlreact-native中文文檔(極客學院) http://wiki.jikexueyuan.com/project/react-native/react-native中文文檔(react
  • 【重學React】動手實現一個react-redux
    react-redux 是什麼react-redux 是 redux 官方 React 綁定庫。它幫助我們連接UI層和數據層。本文目的不是介紹 react-redux 的使用,而是要動手實現一個簡易的 react-redux,希望能夠對你有所幫助。
  • React.js 2016最佳實踐
    譯者按:近幾個月React相關話題依舊火熱,相信越來越多的開發者在嘗試這一項技術,我們團隊也在PC和移動端不斷總結經驗。
  • React 16.8 之 React Hook
    有了 react hook 就不用寫class(類)了,組件都可以用function來寫,不用再寫生命周期鉤子,最關鍵的,不用再面對this了!Hook 規則hook本質也是javaScript函數,但是他在使用的時候需要遵循兩條規則,並且react要求強制執行這兩條規則,不然就會出現奇怪的bug。
  • 十大最受歡迎的 React Native 應用開發編輯器
    而在隨後從事 React Native 開發工作過程中,對相應的編輯器做了一些探索和研究,本文總結了一些非常適合移動應用開發的編輯器和 IDE。1.Atom 常用的包atom-react-native-autocomplete package - 該包針對 React-Native,為 Atom 編輯器提供自動補全功能。atom-react-native-css - 這是一個內置支持 SASS、SCSS 的 React-Native 組件的包。
  • React Hook起飛指南
    所以,一句話總結hook帶來的變革就是:將可復用的最小單元從組件層面進一步細化到邏輯層面。基於這一點優勢,在後面我們看可以看到,基於hook開發的應用裡的所有組件都不會隨業務增長而變得臃腫,因為在hook的世界裡,狀態邏輯和UI是解耦的。UI只需要消費最終計算出來的狀態數據,hook只關注狀態的計算和改變。
  • 超性感的React Hooks(四):useEffect
    •每個React組件初始化時,DOM都會渲染一次•副作用:完成後的一秒鐘,counter加1結合這個思路,代碼實現如下:import React, { useState, useEffect } from 'react';import '.
  • React Status 中文周刊 #26 - Aleph:基於 Deno 的 React 框架
    新年將近,提前預祝大家新年快樂~電腦閱讀,請訪問 https://docschina.org/weekly/react🔥 本周熱門基於 AWS Lambda 的 React 應用服務端渲染 — 通過使用 Lambda 或 Lambda@Edge