React开发需要熟悉的JavaScript特性

2019 年 9 月 14 日 前端之巅
作者 | Kent C. Dodds
译者 | 张健欣
编辑 | 张之栋、Yonie
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}!`) // Hello World!
// this is the same as:
console.log(greeting + ' ' + subject + '!')
// in React:
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})
// this is the same as:
console.log({a: a, b: b, c: c})
// in React:
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
// this is the same as:
function getFive() {
  return 5
}
function addFive(a) {
  return a + 5
}
function divide(a, b) {
  return a / b
}
// in React:
function TeddyBearList({teddyBears}) {
  return (
    <ul>
      {teddyBears.map(teddyBear => (
        <li key={teddyBear.id}>
          <span>{teddyBear.name}</span>
        </li>
      ))}
    </ul>

  )
}

上面的例子中值得一提的是,圆括号 ( 的闭合。这是使用 JSX 时利用箭头函数的隐式返回能力的一种常见方法。

    解构    
解构可能是我最喜欢的 JavaScript 特性之一。我经常解构对象和数组(而且如果你使用 useState,你可能也会这样喜欢这个特性)。我喜欢它强大的表达能力。
// const obj = {x: 3.6, y: 7.8}
// makeCalculation(obj)
function makeCalculation({x, y: d, z = 4}) {
  return Math.floor((x + d + z) / 3)
}
// this is the same as
function makeCalculation(obj) {
  const {x, y: d, z = 4} = obj
  return Math.floor((x + d + z) / 3)
}
// which is the same as
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)
}
// in React:
function UserGitHubImg({username = 'ghost', ...props}) {
  return <img src={`https://github.com/${username}.png`} {...props} />
}

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

一定要读这篇 MDN 文章。你一定会学到一些新东西。当你读完了,尝试用解构方式的一行代码来重构如下代码:


function nestedArrayAndObject() {
  // refactor this to a single line of destructuring...
  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 {} = info // <-- replace the next few `const` lines with this
  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}"`
}
参数默认值
这是我经常使用的另外一个特性。这是为你的函数设定默认值的一种非常有表达力的一种声明方式。
// add(1)
// add(1, 2)
function add(a, b = 0) {
  return a + b
}
// is the same as
const add = (a, b = 0) => a + b
// is the same as
function add(a, b) {
  b = b === undefined ? 0 : b
  return a + b
}
// in React:
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]
}
Rest/Spread
...语法可以被认为是一种“集合”语法,因为它对值集合进行操作。我经常使用这个特性,而且强烈推荐你学习在哪些地方如何使用它。它确实在不同的上下文中表示不同的意思,因此学习其中的细微差别将会帮到你。
const arr = [5, 6, 8, 4, 9]
Math.max(...arr)
// is the same as
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})
// is the same as
console.log(Object.assign({}, obj1, obj2))
function add(first, ...rest) {
  return rest.reduce((sum, next) => sum + next, first)
}
// is the same as
function add() {
  const first = arguments[0]
  const rest = Array.from(arguments).slice(1)
  return rest.reduce((sum, next) => sum + next, first)
}
// in React:
function Box({className, ...restOfTheProps}) {
  const defaultProps = {
    className: `box ${className}`,
    children: 'Empty box',
  }
  return <div {...defaultProps} {...restOfTheProps} />
}
  ES 模块  
如果你使用现代工具构建一个应用程序,它很可能支持模块,那么学习模块是如何生效的就是一个不错的主意,因为任何应用程序,即使是规模非常微小,也很可能需要使用模块来进行代码组织和复用。
export default function add(a, b) {
  return a + b
}
/*
 * import add from './add'
 * console.assert(add(3, 2) === 5)
 */

export const foo = 'bar'
/*
 * import {foo} from './foo'
 * console.assert(foo === 'bar')
 */

export function subtract(a, b) {
  return a - b
}
export const now = new Date()
/*
 * import {subtract, now} from './stuff'
 * console.assert(subtract(4, 2) === 2)
 * console.assert(now instanceof Date)
 */

// in React:
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 :-('
// is the same as
let message
if (bottle.fullOfSoda) {
  message = 'The bottle has soda!'
} else {
  message = 'The bottle may not have soda :-('
}
// in React:
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 会让你的三元条件表达式更易读。

数组方法
数组太棒了,我一直使用数组方法!我可能会经常使用如下方法:
  • find
  • some
  • every
  • includes
  • map
  • filter
  • 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')
// {id: 'dog-2', name: 'Bernese Mountain Dog', ...etc}
dogs.some(dog => dog.temperament.includes('Aggressive'))
// false
dogs.some(dog => dog.temperament.includes('Trusting'))
// true
dogs.every(dog => dog.temperament.includes('Trusting'))
// false
dogs.every(dog => dog.temperament.includes('Intelligent'))
// true
dogs.map(dog => dog.name)
// ['Poodle', 'Bernese Mountain Dog', 'Labrador Retriever']
dogs.filter(dog => dog.temperament.includes('Faithful'))
// [{id: 'dog-1', ..etc}, {id: 'dog-2', ...etc}]
dogs.reduce((allTemperaments, dog) => {
  return [...allTemperaments, ...dog.temperaments]
}, [])
// [ 'Intelligent', 'Active', 'Alert', ...etc ]
// in React:
function RepositoryList({repositories, owner}) {
  return (
    <ul>
      {repositories
        .filter(repo => repo.owner === owner)
        .map(repo => (
          <li key={repo.id}>{repo.name}</li>
        ))}
    </ul>

  )
}
Promises 和 async/await

这是一个很大的主题,它可能需要花费一些时间练习和使用它们才能用好它们。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}` // this would not be executed
    } 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)
}
// This is the mothership of all things asynchronous
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)
  })
}
// in React:
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

登录查看更多
0

相关内容

React.js(React)是 Facebook 推出的一个用来构建用户界面的 JavaScript 库。

Facebook开源了React,这是该公司用于构建反应式图形界面的JavaScript库,已经应用于构建Instagram网站及 Facebook部分网站。最近出现了AngularJS、MeteorJS 和Polymer中实现的Model-Driven Views等框架,React也顺应了这种趋势。React基于在数据模型之上声明式指定用户界面的理念,用户界面会自动与底层数据保持同步。与前面提及 的框架不同,出于灵活性考虑,React使用JavaScript来构建用户界面,没有选择HTML。Not Rest

【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
最新《自动微分手册》77页pdf
专知会员服务
100+阅读 · 2020年6月6日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
机器学习速查手册,135页pdf
专知会员服务
338+阅读 · 2020年3月15日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
69+阅读 · 2020年1月17日
注意力机制介绍,Attention Mechanism
专知会员服务
168+阅读 · 2019年10月13日
机器学习入门的经验与建议
专知会员服务
92+阅读 · 2019年10月10日
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
2020年你应该知道的8种前端JavaScript趋势和工具
前端之巅
5+阅读 · 2019年6月9日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
Python3.8新特性概览
Python程序员
4+阅读 · 2018年12月8日
.NET Core 环境下构建强大且易用的规则引擎
暗通沟渠:Multi-lingual Attention
我爱读PAMI
7+阅读 · 2018年2月24日
前端高性能计算(4):GPU加速计算
前端大全
7+阅读 · 2017年10月26日
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
Talking-Heads Attention
Arxiv
15+阅读 · 2020年3月5日
Relational recurrent neural networks
Arxiv
8+阅读 · 2018年6月28日
VIP会员
相关VIP内容
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
最新《自动微分手册》77页pdf
专知会员服务
100+阅读 · 2020年6月6日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
【实用书】Python爬虫Web抓取数据,第二版,306页pdf
专知会员服务
117+阅读 · 2020年5月10日
机器学习速查手册,135页pdf
专知会员服务
338+阅读 · 2020年3月15日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
69+阅读 · 2020年1月17日
注意力机制介绍,Attention Mechanism
专知会员服务
168+阅读 · 2019年10月13日
机器学习入门的经验与建议
专知会员服务
92+阅读 · 2019年10月10日
相关资讯
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
2020年你应该知道的8种前端JavaScript趋势和工具
前端之巅
5+阅读 · 2019年6月9日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
Python3.8新特性概览
Python程序员
4+阅读 · 2018年12月8日
.NET Core 环境下构建强大且易用的规则引擎
暗通沟渠:Multi-lingual Attention
我爱读PAMI
7+阅读 · 2018年2月24日
前端高性能计算(4):GPU加速计算
前端大全
7+阅读 · 2017年10月26日
Vue.js 很好,但是比 Angular 或 React 更好吗?
程序猿
3+阅读 · 2017年8月27日
Top
微信扫码咨询专知VIP会员