react 讀書筆記

来源:https://www.cnblogs.com/sk-3/archive/2020/05/17/12903395.html
-Advertisement-
Play Games

"來源掘金小冊 react實戰:設計模式和最佳實踐" react設計思想 1. 屬性展開 保留當前組件需要的props,並且使其他的props傳遞下去 2. 在react中,界面完全由數據驅動 3. 在react中,一切都是組件 4. props是react組件之間通訊的基本方式 設計react組件 ...


來源掘金小冊 - react實戰:設計模式和最佳實踐

react設計思想

  1. 屬性展開 - 保留當前組件需要的props,並且使其他的props傳遞下去
  var obj = {a: 1, b: 2, c: 3, d: 4, e: 5}
  const { a, ...other } = obj
  console.log(other)  // {b: 2, c: 3, d: 4, e: 5}
  1. 在react中,界面完全由數據驅動
  2. 在react中,一切都是組件
  3. props是react組件之間通訊的基本方式
  // 可以實現記錄用戶訪問路徑操作信息,每次進入某個頁面或者功能的時候都會訪問一個線上資源
  // a.js
  export default Beacon extends React.Component {
    componentDidMount() {
      const beacon = new Image()
      beacon.src = 'https://sxc.image/i.png'
    }
    
    render() {
      return null
    }
  }
  // b.js
  render() {
    <div>
      <Beacon/>
    </div>
  }

  // 代碼組織方式優化 - renderXXX函數訪問的是同樣的props和state,代碼耦合嚴重
  class StopWatch extends React.Component {

    renderClock() {

    }

    renderButtons() {

    }

    renderSplitTimes() {

    }
    
    render() {
      const Clock = this.renderClock()
      const Buttons = this.renderButtons()
      const SplitTimes = this.renderSplitTimes()

      return (
        <div>
          {Clock}
          {Buttons}
          {SplitTimes}
        </div>
      )
    }
  }
  // 更好的組織方式
  class StopWatch extends React.Component {
    render() {
      return (
        <div>
          <Clock />
          <Buttons />
          <SplitTimes />
        </div>
      )
    }
  }
  const Clock = (props) = {

  }
  const Buttons = (props) => {

  }
  const SplitTimes = (props) => {

  }

設計react組件原則及最佳實踐

1. 保持介面小,props數量要少
2. 根據數據邊界來劃分組件,充分利用組合
3. 把state往上層組件提取,讓下層組件只需要實現為純函數
4. 避免renderXXXX函數
5. 給回調函數類型的props加統一首碼,比如on or handle - onStart
6. 使用propTypes來定義組件的props
7. 儘量每個組件都有自己專屬的文件
8. 用解構賦值的方式獲取參數props的屬性 - const { a, b } = { a: 1, b: 2 }
9. 利用屬性初始化來定義state和成員函數 - 給預設值 const { data = [] } = this.props
  /*
    1. 儘量不要在jsx中寫內聯函數
    2. 每次渲染,都會產生新的函數對象
    3. 每次傳給組件的props(方法,數據,狀態等)都是新的,無法通過shouldComponentUpdate對props的檢查來避免重覆渲染
  */
  <Buttons
    activated={this.state.isStarted}
    onStart={() => {/* TODO */}}
    onReset={() => {/* TODO */}}
  />
  /*
    1. style屬性的使用
    2. 內聯樣式在組件每次渲染時都會創建一個新的style對象
    3. 如果樣式不發生改變,應該把style對象提取到組件之外,可以重用一個對象
  */
  // bad
  const Clock = (props) => {
    return <h1 style={color: '#ccc'}>小姐姐真好看<h1/>
  }
  // good
  const style = {
    color: '#ccc'
  }
  const Clock = (props) => {
    return <h1 style={style}>小姐姐真好看<h1/>
  }

組件樣式

1. 不同組件中相同的元素樣式相互影響,a.js與b.js中都有h1組件,樣式之間會相互影響
2. 添加styled-jsx/styled-component支持
  // a.js
  index.css
  h1: {
    color: red
  }
  <h1>a</h1>
  // b.js
  <h1>b</h1>
  
  // a.js
  .a h1: {
    color: red
  }
  <div className='a'>
    <h1>a</h1>
  <div/>
  // b.js
  <div className='b'>
    <h1>a</h1>
  <div/>

狀態組件與無狀態組件分割

1. 軟體設計原則"責任分離",就是讓一個模塊責任儘量少,每個模塊專註於一個功能,有利於代碼的維護
2. react中數據渲染頁面,UI = f(data),但是儘量把獲取和管理數據與界面渲染分開,即把獲取數據與管理數據的邏輯放在父組件,把渲染界面的邏輯放在子組件
3. A組件渲染B組件時,即使props傳入一樣,B組件也會完整走一遍渲染流程
4. 函數形式的react組件,好處是不需要管理state,占用資源少,但是函數組件無法利用shouldComponentUpdate來優化減少渲染
5. PureComponent中實現的shouldComponentUpdate會對傳入的參數進行淺比較,當傳入的props為一個對象之類的,比如由{a: 1, b: 2} => {a: 2, b: 2},可能會出現UI未更新的情況出現
6. shouldComponentUpdate函數,每次渲染render函數之前會被調用,返回true繼續渲染,返回false立刻停止,可以對深層次的數據處理
7. 在使用PureComponent時,儘量在render定義之外創建所有對象,數組和函數,並確保在各種調用間,不發生更改 - 參考table例子
8. React.memo淺比較
  export default class A extends React.Component {
    state = {
      joke: null
    }

    componentDidMount() {
      fetch(url, {header: {'Accept': 'application/json'}})
        .then(res => {
          return res.json()
        })
        .then(json => {
          this.setState({joke: json.joke})
        })
    }

    render() {
      return <B value={this.state.joke} />
    }
  }

  export default class B extends React.Component {
    render() {
      return (
        <div>
          <img src={url} />
          {this.props.value || 'loading...'}
        </div>
      )
    }
  }
  <Table
    // map每次返回一個新數組,淺比較失敗
    rows={rows.map()}
    // 枚舉對象總不相同 - 儘量不寫行內樣式
    style={{color: '#ccc'}}
    // 箭頭函數每次都會重新渲染 - 組件層級不通過箭頭函數綁定事件
    onUpdate={() => {}}
  />

高階組件

待補充...

render props模式

1. render props的形式
2. render props其實就是依賴註入
3. 如何利用render props實現共用組件之間的邏輯
4. 依賴註入:**當邏輯A依賴邏輯B時,如果讓A直接依賴B,A做不到通用。依賴註入就是把B的邏輯以函數形式傳遞給A,讓A和B之間只需要對函數介面達成一致 - 組件A和B之間,不是把B組件寫在A組件中,而是通過把B組件當參數傳到A組件當中**
  // 用戶登錄與未登錄情況下顯示不同的組件
  const Auth = (props) => {
    const userName = getUserName()
    if(userName) {
      const allProps = {userName, ...props}
      return (
        <React.Fragment>
          {props.login(allProps)}
        </React.Fragment>
      )
    } else {
      return (
        <React.Fragment>
          {props.noLogin(props)}
        </React.Fragment>
      )
    }
  }

  <Auth
    login={({userName}) => <h1>Hello {userName}</h1>}
    noLogin={() => <h1>Please login</h1>}
  />

提供者模式

1. 提供者模式,為了**解決組件間跨層級的信息傳遞**,A-B-C-D-...-X,當數據要從A傳遞到X時,通過props傳遞時,會經過B-C-D...,然而在B-C-D...中不需要使用props中的數據,而且組件在變動時,容易出現props傳遞錯誤的情況出現
2. 提供者模式,本質由2個角色組成,一個叫‘提供者’,一個叫‘消費者’,提供者(A)位於組件樹靠上的位置,消費者(X)處於靠下的位置
3. 實現方式,通過**react提供的context功能進行實現(v16.3.0+),context功能可以創造一個‘上下文’,在這個上下文之中的所有組件都可以訪問到同樣的數據**
4. 參考react-app中x2代碼

組合組件

1. 模式(Pattern) = 問題場景(Context) + 解決方法(Solution)
2. 解決的問題,**父組件想傳遞一些信息給子組件,但是通過props傳遞又很麻煩時**

組件狀態

1. UI = f(data),data = props + state,props代表外部傳進來的數據,state代表組件內部狀態
2. 什麼樣的數據可以存放在成員變數中?
3. 如果數據由外部傳入,放在props中
4. **如果是內部組件數據,這個數據的更改是否應該立刻引發一次組件的重新渲染,如果是,放在state中,不是就放在成員變數中**
5. state不會被同步修改,在react的生命周期中或者處理函數中同步調用,setState不會立即同步state和重覆渲染,但是如果setState由其他條件引發,就有可能不是這樣了 - 在生命周期中或者事件函數中調用時,react會打開一個類似標記的東西,標記打開的過程中,setState調用都是往任務隊列里放任務,當函數調用結束時,批量處理任務隊列,關閉標記
6. 函數式setState -  當setState的第一個參數為函數時,任務列表上增加的就是一個可執行的任務函數,react沒處理完一個任務,都會更新一次state,然後把新的state傳遞給這個任務函數
  // 代碼1
  class Foo extends Component {
    foo = 'foo'

    render() {
      return <div>{this.foo}</>
    }
  }
  // 代碼2
  this.state = {
    count: 0
  }

  this.setState({count: 1})
  console.log(this.state.count) // 0
  // 代碼3
  setTimeout(() => {
    this.setState({count: 2})
    console.log(this.state.count) // 2
  })
  // 代碼4 - 結果為1 三個任務都給了this.state.count一個值
  this.state = {
    count: 0
  }
  this.setState({count: this.state.count + 1})
  this.setState({count: this.state.count + 1})
  this.setState({count: this.state.count + 1})
  // 代碼5 - 函數式setState,結果為3
  // this.setState((preState, props) => ({})
  function increment(state, props) {
    return {count: state.count + 1}
  }
  this.state = {
    count: 0
  }
  this.setState(increment)
  this.setState(increment)
  this.setState(increment)

redux使用模式

1. 使用場景 - 複雜應用下的狀態維護,類似於一個全局的store,**並且store只有接受某些‘事件’(action),才可以修改store上的數據,store對這些‘事件’的響應,就是修改狀態(修改狀態的函數reducer)**
2. 事件(action) - 響應函數(reducer) -store
3. 對於某個狀態,是放在store中還是組件自身狀態中?
4. 看狀態是否會被多個react組件共用 - 不同級組件件的數據共用
5. 看這個組件被unmount之後重新被mount,之前的狀態是否需要保留 - 組件銷毀後又重新渲染,之前的輸入是否要保留
6. 代碼組織方式 - 基於角色分類(modal,services,view,action,reducer)和基於功能分類(安裝功能所在模塊分類)
7. connect函數接受兩個參數,一個mapStateToProps是把Store上的state映射為props,另一個mapDispatchToProps是把回調函數類型的props映射為派發action,connect函數調用會產生一個‘高階組件’
8. react-redux中使用了三個模式 - 提供者模式,高階組件,有狀態組件和無狀態組件
  // 代碼1
  import { createStore } from 'redux'
  import { Provider } from 'react-redux'
  import store from './store'

  const store = createStore(store)

  <Provider store={store}>
    {Provider之下的所有組件都可以connect到給定的store}
  </Provider>
  // 代碼2
  const Button = ({count, onIncrement}) => {
    return (
      <div>
        <div>{count}</div>
        <button onClick={onIncrement}>+</button>
      </div>
    )
  }
  // 代碼3
  import { connect } from 'react-redux'

  const mapStateToProps = (state) => {
    return {
      count: count + 1
    }
  }

  const mapDispatchToProps = (dispatch) => {
    onIncrement: () => dispatch({type: 'INCREMENT'})
  }

  const Counter = connect(mapStateToProps, mapDispatchToProps)(Button)

mobx使用模式

待補充...

redux與mobx模式對比

待補充...

路由 react router

1. 單頁應用 - 把URL映射到對應的頁面來處理,頁面之間切換做到局部更新
2. 動態路由 - 指的路由規則不是預先確定的,而是在渲染過程中確定的(React Router v4)
3. 靜態路由 - 路由規則是固定的

未完待續...


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.安裝部署 "1.Zabbix部署" "2.Nessus簡介與安裝" "3.Ceph安裝" "4.Graylog 安裝" "5.Centos6.10 安裝Python 2.7.16" 更新中... 二.Linux運維 更新中... ...
  • BIOS 中英文對照表 轉載於https://www.dell.com/support/article/zh-cn/sln262122/bios-%E4%B8%AD%E8%8B%B1%E6%96%87%E5%AF%B9%E7%85%A7%E8%A1%A8?lang=zh 註意:機型不同 BIOS 版 ...
  • Redis 系列: 1. "Redis系列(一)Redis入門" 2. "Redis系列(二)Redis的8種數據類型" 3. "Redis系列(三)Redis的事務和Spring Boot整合" 4. "Redis系列(四)Redis配置文件和持久化" 5. "Redis系列(五)發佈訂閱模式、主 ...
  • 假設有一個用戶表 user,數據如下: 1、查詢表中 uid 重覆的數據 SELECT id, uid, name FROM USER WHERE uid IN (SELECT uid FROM USER GROUP BY uid HAVING COUNT(uid) > 1); 2、查詢表中重覆數據 ...
  • 在SQL Server 2017的錯誤日誌中出現"Parallel redo is started for database 'xxx' with worker pool size [2]"和“Parallel redo is shutdown for database 'xxx' with wor... ...
  • Redis 伺服器將所有的資料庫都保存在伺服器狀態redisServer結構的db數組中,db數組的每個項都是一個redisDB: struct redisServer{ //一個數組保存著伺服器中的所有資料庫 redisDb *db; //資料庫的個數 int dbnum; } dbnum:伺服器 ...
  • 一、使用碎片來進行一個最佳實踐,即我們寫一個新聞的app 1.首先先建立一個新聞類 package com.example.fragmentbestpractice; ​ public class News { private String title; private String content ...
  • 本文章將記錄Objective-C中消息傳遞和轉發機制、Method Swizzling的相關資料,如有錯誤歡迎指出~ Objective-C 本質上是一種基於 C 語言的領域特定語言。C 語言是一門靜態語言,其在編譯時決定調用哪個函數。而 Objective-C 則是一門動態語言,其在編譯時不能決 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...