React開發需要熟悉的JavaScript特性

2022-02-07 前端之巔
React 與其它框架相對,與 JavaScript 的關係更密切,因此學習 JavaScript 特性可以更加高效地使用 JavaScript 構建應用程式。本文將主要介紹作者最喜歡且最常用的一些 JavaScript 特性。

與我使用過的其它框架相比,我最喜歡 React 的一點是,當你使用它時與 JavaScript 的密不可分。不存在模版 DSL(JSX 直接編譯成 JavaScript),組件 API 在添加了 React Hooks 後變得更加簡單,而且這個框架在它想要解決的核心 UI 關注點之外提供的抽象概念很少。

因此,學習 JavaScript 特性對於您更高效地使用 React 構建應用程式絕對是明智的。下面是一些我建議您花一些時間學習的 JavaScript 特性,從而讓你儘可能高效地使用 React 工作。

React Hooks: https://reactjs.org/hooks  

const greeting = 'Hello'
const subject = 'World'
console.log(`${greeting} ${subject}!`)

console.log(greeting + ' ' + subject + '!')

function Box({className, ...props}) {
  return <div className={`box ${className}`} {...props} />
}

這是如此常見和有用,以至於我現在幾乎不假思索就會這樣做。

const a = 'hello'
const b = 42
const c = {d: [true, false]}
console.log({a, b, c})

console.log({a: a, b: b, c: c})

function Counter({initialCount, step}) {
  const [count, setCount] = useCounter({initialCount, step})
  return <button onClick={setCount}>{count}</button>
}

箭頭函數是在 JavaScript 中編寫函數的另外一種方式,但是他們確實有一些語法區別。幸運的是,在 React 環境下,如果我們在項目中使用鉤子(而不是類)的話,我們不需要太關心這個區別。箭頭函數允許簡短的匿名函數和隱式返回,因此你將看到並希望大量使用箭頭函數。

const getFive = () => 5
const addFive = a => a + 5
const divide = (a, b) => a / b

function getFive() {
  return 5
}
function addFive(a) {
  return a + 5
}
function divide(a, b) {
  return a / b
}

function TeddyBearList({teddyBears}) {
  return (
    <ul>
      {teddyBears.map(teddyBear => (
        <li key={teddyBear.id}>
          <span>{teddyBear.name}</span>
        </li>
      ))}
    </ul>
  )
}

上面的例子中值得一提的是,圓括號 ( 的閉合。這是使用 JSX 時利用箭頭函數的隱式返回能力的一種常見方法。

解構可能是我最喜歡的 JavaScript 特性之一。我經常解構對象和數組(而且如果你使用useState,你可能也會這樣喜歡這個特性)。我喜歡它強大的表達能力。



function makeCalculation({x, y: d, z = 4}) {
  return Math.floor((x + d + z) / 3)
}

function makeCalculation(obj) {
  const {x, y: d, z = 4} = obj
  return Math.floor((x + d + z) / 3)
}

function makeCalculation(obj) {
  const x = obj.x
  const d = obj.y
  const z = obj.z === undefined ? 4 : obj.z
  return Math.floor((x + d + z) / 3)
}

function UserGitHubImg({username = 'ghost', ...props}) {
  return <img src={`https://github.com/${username}.png`} {...props} />
}

MDN: Destructuring assignmenthttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment 

一定要讀這篇 MDN 文章。你一定會學到一些新東西。當你讀完了,嘗試用解構方式的一行代碼來重構如下代碼:

function nestedArrayAndObject() {
  
  const info = {
    title: 'Once Upon a Time',
    protagonist: {
      name: 'Emma Swan',
      enemies: [
        {name: 'Regina Mills', title: 'Evil Queen'},
        {name: 'Cora Mills', title: 'Queen of Hearts'},
        {name: 'Peter Pan', title: `The boy who wouldn't grow up`},
        {name: 'Zelena', title: 'The Wicked Witch'},
      ],
    },
  }
  
  const title = info.title
  const protagonistName = info.protagonist.name
  const enemy = info.protagonist.enemies[3]
  const enemyTitle = enemy.title
  const enemyName = enemy.name
  return `${enemyName} (${enemyTitle}) is an enemy to ${protagonistName} in "${title}"`
}

這是我經常使用的另外一個特性。這是為你的函數設定默認值的一種非常有表達力的一種聲明方式。



function add(a, b = 0) {
  return a + b
}

const add = (a, b = 0) => a + b

function add(a, b) {
  b = b === undefined ? 0 : b
  return a + b
}

function useLocalStorageState({
  key,
  initialValue,
  serialize = v => v,
  deserialize = v => v,
}) {
  const [state, setState] = React.useState(
    () => deserialize(window.localStorage.getItem(key)) || initialValue,
  )
  const serializedState = serialize(state)
  React.useEffect(() => {
    window.localStorage.setItem(key, serializedState)
  }, [key, serializedState])
  return [state, setState]
}

...語法可以被認為是一種「集合」語法,因為它對值集合進行操作。我經常使用這個特性,而且強烈推薦你學習在哪些地方如何使用它。它確實在不同的上下文中表示不同的意思,因此學習其中的細微差別將會幫到你。

const arr = [5, 6, 8, 4, 9]
Math.max(...arr)

Math.max.apply(null, arr)
const obj1 = {
  a: 'a from obj1',
  b: 'b from obj1',
  c: 'c from obj1',
  d: {
    e: 'e from obj1',
    f: 'f from obj1',
  },
}
const obj2 = {
  b: 'b from obj2',
  c: 'c from obj2',
  d: {
    g: 'g from obj2',
    h: 'g from obj2',
  },
}
console.log({...obj1, ...obj2})

console.log(Object.assign({}, obj1, obj2))
function add(first, ...rest) {
  return rest.reduce((sum, next) => sum + next, first)
}

function add() {
  const first = arguments[0]
  const rest = Array.from(arguments).slice(1)
  return rest.reduce((sum, next) => sum + next, first)
}

function Box({className, ...restOfTheProps}) {
  const defaultProps = {
    className: `box ${className}`,
    children: 'Empty box',
  }
  return <div {...defaultProps} {...restOfTheProps} />
}

如果你使用現代工具構建一個應用程式,它很可能支持模塊,那麼學習模塊是如何生效的就是一個不錯的主意,因為任何應用程式,即使是規模非常微小,也很可能需要使用模塊來進行代碼組織和復用。

export default function add(a, b) {
  return a + b
}

export const foo = 'bar'

export function subtract(a, b) {
  return a - b
}
export const now = new Date()


import React, {Suspense, Fragment} from 'react'

我對這個語法進行了全面的講解,你可以在此觀看:https://www.youtube.com/watch?v=kTlcu16rSLc&list=PLV5CVI1eNcJgNqzNwcs4UKrlJdhfDjshf。

我喜歡三元條件表達式,因為它們的聲明方式太美了,特別是在 JSX 中。

onst message = bottle.fullOfSoda
  ? 'The bottle has soda!'
  : 'The bottle may not have soda :-('

let message
if (bottle.fullOfSoda) {
  message = 'The bottle has soda!'
} else {
  message = 'The bottle may not have soda :-('
}

function TeddyBearList({teddyBears}) {
  return (
    <React.Fragment>
      {teddyBears.length ? (
        <ul>
          {teddyBears.map(teddyBear => (
            <li key={teddyBear.id}>
              <span>{teddyBear.name}</span>
            </li>
          ))}
        </ul>
      ) : (
        <div>There are no teddy bears. The sadness.</div>
      )}
    </React.Fragment>
  )
}

我知道三元條件表達式會受到一些人的反感,他們不得不忍受在 prettier 清理我們的代碼之前理解三元條件表達式。如果你還沒有使用 prettier,我強烈建議你使用。Prettier 會讓你的三元條件表達式更易讀。

數組太棒了,我一直使用數組方法!我可能會經常使用如下方法:

reduce

const dogs = [
  {
    id: 'dog-1',
    name: 'Poodle',
    temperament: [
      'Intelligent',
      'Active',
      'Alert',
      'Faithful',
      'Trainable',
      'Instinctual',
    ],
  },
  {
    id: 'dog-2',
    name: 'Bernese Mountain Dog',
    temperament: ['Affectionate', 'Intelligent', 'Loyal', 'Faithful'],
  },
  {
    id: 'dog-3',
    name: 'Labrador Retriever',
    temperament: [
      'Intelligent',
      'Even Tempered',
      'Kind',
      'Agile',
      'Outgoing',
      'Trusting',
      'Gentle',
    ],
  },
]
dogs.find(dog => dog.name === 'Bernese Mountain Dog')

dogs.some(dog => dog.temperament.includes('Aggressive'))

dogs.some(dog => dog.temperament.includes('Trusting'))

dogs.every(dog => dog.temperament.includes('Trusting'))

dogs.every(dog => dog.temperament.includes('Intelligent'))

dogs.map(dog => dog.name)

dogs.filter(dog => dog.temperament.includes('Faithful'))

dogs.reduce((allTemperaments, dog) => {
  return [...allTemperaments, ...dog.temperaments]
}, [])


function RepositoryList({repositories, owner}) {
  return (
    <ul>
      {repositories
        .filter(repo => repo.owner === owner)
        .map(repo => (
          <li key={repo.id}>{repo.name}</li>
        ))}
    </ul>
  )
}

這是一個很大的主題,它可能需要花費一些時間練習和使用它們才能用好它們。Promises 在 JavaScript 生態系統中無處不在,而且由於 React 在這個系統中的牢固地位,因此 Promises 在 React 中也無處不在(事實上,React 內部本身也使用 promises)。

Promises 幫你處理異步代碼,並從許多 DOM API 和第三方庫中解脫出來。Async/await 是處理 promises 的一種特殊語法。這兩者相輔相成。

function promises() {
  const successfulPromise = timeout(100).then(result => `success: ${result}`)
  const failingPromise = timeout(200, true).then(null, error =>
    Promise.reject(`failure: ${error}`),
  )
  const recoveredPromise = timeout(300, true).then(null, error =>
    Promise.resolve(`failed and recovered: ${error}`),
  )
  successfulPromise.then(log, logError)
  failingPromise.then(log, logError)
  recoveredPromise.then(log, logError)
}
function asyncAwaits() {
  async function successfulAsyncAwait() {
    const result = await timeout(100)
    return `success: ${result}`
  }
  async function failedAsyncAwait() {
    const result = await timeout(200, true)
    return `failed: ${result}`
  }
  async function recoveredAsyncAwait() {
    let result
    try {
      result = await timeout(300, true)
      return `failed: ${result}` 
    } catch (error) {
      return `failed and recovered: ${error}`
    }
  }
  successfulAsyncAwait().then(log, logError)
  failedAsyncAwait().then(log, logError)
  recoveredAsyncAwait().then(log, logError)
}
function log(...args) {
  console.log(...args)
}
function logError(...args) {
  console.error(...args)
}

function timeout(duration = 0, shouldReject = false) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (shouldReject) {
        reject(`rejected after ${duration}ms`)
      } else {
        resolve(`resolved after ${duration}ms`)
      }
    }, duration)
  })
}

function GetGreetingForSubject({subject}) {
  const [isLoading, setIsLoading] = React.useState(false)
  const [error, setError] = React.useState(null)
  const [greeting, setGreeting] = React.useState(null)
  React.useEffect(() => {
    async function fetchGreeting() {
      try {
        const response = await window.fetch('https://example.com/api/greeting')
        const data = await response.json()
        setGreeting(data.greeting)
      } catch (error) {
        setError(error)
      } finally {
        setIsLoading(false)
      }
    }
    setIsLoading(true)
    fetchGreeting()
  }, [])
  return isLoading ? (
    'loading...'
  ) : error ? (
    'ERROR!'
  ) : greeting ? (
    <div>
      {greeting} {subject}
    </div>
  ) : null
}

在構建 React 應用程式時,當然還有許多有用的語言特性,但是這些是我最喜歡並且自己一直重複使用的一些特性。我希望這些對你也有用。

如果你希望深入了解這些特性,我有一個我在 PayPal 工作時主持和記錄的 JavaScript 研討會,可能會對你有所幫助:https://www.youtube.com/playlist?list=PLV5CVI1eNcJgUA2ziIML3-7sMbS7utie5

英文原文:https://kentcdodds.com/blog/javascript-to-know-for-react

相關焦點

  • React-Router v6 新特性解讀及遷移指南
    前言18 年初,React Router的主要開發人員創建一個名為Reach Router的輕量級替代方案。原來是相互抗衡的,卻沒想React Router直接拿來合併(真香!)用useNavigate代替useHistory。
  • 從 Vue2.0 到 React17 —— React 開發入門
    因為我用Vue2.0開發項目已經四年了,故用Vue2.0開發項目的思路來學習React。前端項目是由一個個頁面組成的,對於Vue來說,一個頁面是由多個組件構成的,頁面本身也是一個路由組件。對於React來說也是如此。
  • 60+ 實用 React 工具庫,助力你高效開發!
    npm地址:https://www.npmjs.com/package/redux2. react-reduxRedux 官方提供的 React 綁定庫。具有高效且靈活的特性。npm地址:https://www.npmjs.com/package/react-tabs24. rebassRebass是一個用於構建響應式WEB應用的React UI工具包,它有60多種可定製的基礎組件,而且風格樣式分離,不需要編寫自定義的CSS。
  • 我讀完了React的API,並為新手送上了一些建議
    更重要的是,React 是一個由 Jordan Walke 創建的 Facebook 開源項目,這個項目由一些頗具野心的年輕開發人員主導——其中包括 Dan Abramov,他經常會隱晦地解釋這個庫背後的理念,(社交)媒體上關於 React 的話題幾乎都能找到他的身影;還有 Brain Vaughn,他從圖形設計領域轉向了編程工作,構建了 react-virtualized
  • Java、C/C++、JavaScript、PHP、Python,到底用來開發什麼?
    java常常跟」企業」聯繫在一起,因為具備一些很好的語言特性, 以及豐富的框架,在企業應用中最被青睞,你總可以聽到關於J2EE, JSP, Hibernate之類的東西的討論。同時, java在手機領域也有一席之地,在普遍智能化之前,很多手機就是以支持java應用作為賣點的,而智慧型手機爆發之後,java手機主場變成了android, 作為安卓的標準程式語言而存。
  • Kotlin要支持iOS開發和Web開發了,這是要全棧?
    此外,create-react-kotlin-app 也值得一提,這是一套用於利用 React.js 在 Kotlin 當中創建現代 Web 應用程式的工具集。利用 create-react-kotlin-app,您可以在無需費心於項目設置與配置構建工作的前提下,專注於快速投身客戶端應用開發工作,同時享受到靜態類型語言優勢以及由 JavaScript 生態系統帶來的強大資源儲備。
  • 精通react/vue組件設計之配合React Portals實現一個(Drawer)組件
    通過組件的設計過程,大家會接觸到一個完成健壯的組件設計思路和方法,也能在實現組件的過程逐漸對react/vue的高級知識和技巧有更深的理解和掌握,並且在企業實際工作做遊刃有餘.之所以會寫組件設計相關的文章,是因為作為一名前端優秀的前端工程師,面對各種繁瑣而重複的工作,我們不應該按部就班的去"辛勤勞動",而是要根據已有前端的開發經驗,總結出一套自己的高效開發的方法.
  • React v17.0 正式發布!
    無新特性React v17 的發布非比尋常,因為它沒有增加任何面向開發者的新特性。但是,這個版本會使得 React 自身的升級變得更加容易。注意我們將其他特性推遲到了 React v17 之後。這個版本的目標就是實現漸進式升級。如果升級到 17 很困難,那就違背了此版本的目的。事件委託的變更為了實現漸進式升級,我們需要對 React 的事件系統進行修改。
  • 雲音樂 React Native 體系建設與發展
    自動部署舊部署平臺原有 RN 部署平臺沒有實現自動部署,發布一個 RN 應用需要做以下事情執行兼容性腳本為了支持低版本如 iOS8,需要手動修改本地 node_modules 裡面相關源碼。除了背景圖的語法需要修改之外,還有多少語法需要兼容修改我們不得而知。面對這種範圍不清楚,改動時間又非常緊張的情況,如果使用人工方式不僅效率低下進度也不可控。
  • JavaScript開發重型跨平臺應用以及架構
    這裡不得不提到vsCode,它其實就是用ELectron開發,基於TypeScript。當然肯定使用了不少C++插件,說到這裡,留下傷心的眼淚,最近也是被折磨得很難受成功開發一個重型應用的好處出去面試基本上很容易成功,特別是專業性強的崗位,例如你在QQ開發了十幾年,你根本不用出去找工作,當然你應該也不會跑技術全面,複雜場景你都能hold住有能吹的地方,可以跟誰說:我開發的東西,多少萬人在用,老了還能吹。
  • 超性感的React Hooks(三):useState
    單向數據流和angular雙向綁定不同,React採用自上而下單向數據流的方式,管理自身的數據與狀態。在單向數據流中,數據只能由父組件觸發,向下傳遞到子組件。需要注意的是,setCounter接收的值可以是任意類型,無論是什麼類型,每次賦值,counter得到的,都是新傳入setCounter中的值。舉個例子,如果counter是一個引用類型。
  • 精通React/Vue系列之帶你實現一個功能強大的通知提醒框
    其他業務類型熟悉以上分類法是設計任何組件系統的前提,不管你是從零到一開發前端團隊的UI庫,還是基於已有組件庫二次開發業務組件,以上分類法則同樣適用。如果對設計模式不是很了解,可以移步:15分鐘帶你了解前端工程師必知的javascript設計模式(附詳細思維導圖和源碼).
  • 28個頂級的React UI組件庫,請查收!
    ,其組件使用可靠的開發工作流程來構建漂亮而實用的 Web 項目。需要注意的是,開發者需要使用 props.children 來組合內容,而不是通過命名的 props 傳給組件。需要注意的是,這些組件不會自己導入任何樣式,所以用戶需要使用 carbon-components 中的 scss 或 css 來引入組件的樣式。
  • 【Hooks】:[組]Awesome React Hooks
    :https://kentcdodds.com/blog/react-hooks-whats-going-to-happen-to-render-propsState Management with React Hooks — No Redux or Context API:https://medium.com/javascript-in-plain-english
  • 精讀《高性能 javascript》
    前言本期我來給大家推薦的書是《高性能JavaScript》,在這本書中我們能夠了解 javascript 開發過程中的性能瓶頸,如何提升各方面的性能
  • 新手入門系列之-React / Vue 應用持續集成Docker 化
    樸素的Dockerfile 首先準備一個有標準運行指令的Web應用,用腳手架creat-react-app或Vue CLI等生成的即可。/web/# 暴露容器內部訪問埠,根據項目變動EXPOSE 8080## 如果是Vue CLi,則換成 yarn serveCMD ["npm", "start"]是的,開發環境在Docker 部署,關鍵配置就那麼幾行。
  • React.js 性能分析
    一個交互追蹤,需要包含一個描述(例如:添加購物車按鈕被點擊)、一個時間戳和一個回調函數,在回調函數中你可以定義一些和該交互相關的邏輯。在「影片排期應用」中就有一個添加電影到播放列表的「+」號按鈕,這個就是一個交互按鈕。
  • 一名 Vue 程式設計師總結的 React 基礎
    Hooks 不需要寫 render 函數。要注意的一點是,即使 Hooks 不需要寫 render, 沒有用到 React.xxx,組件內還是要import React from "react";的(至於原因,後續深入 Hooks 學一下,大哥們也可以解釋下)。React 官方也說了,後續的版本會優化掉這一點。
  • 通過與React的簡單對比來入門Flutter
    作者 | ELab.lijianye出品 | ELab團隊(ID:gh_b1857b91fe44)Flutter簡介Flutter是谷歌開源的移動端應用開發框架,採用Dart語言作為開發語言,主要的特點是跨平臺,高性能,高保真。
  • 6個常用的React組件庫
    如果你不熟悉 React,那麼它是一個很好的入門庫。對於經驗更豐富的開發人員來說,他們可能會去研究 styled-components / Emotion。有兩個流行的庫帶有 Bootstrap 的 React 綁定,我個人僅使用 Reactstrap。