使用 React 要懂的 JavaScript 特性[每日前端夜话0xB3]

2019年8月27日 351点热度 0人点赞 0条评论
每日前端夜话0xB3

每日前端夜话,陪你聊前端。

每天晚上18:00准时推送。

正文共:2320 字

预计阅读时间:13 分钟

作者:Kent C. Dodds

翻译:疯狂的技术宅

来源:kentcdodds

图片

与我使用的其他框架相比,我最喜欢 React 的原因之一就是它对 JavaScript 的暴露程度。没有模板DSL( JSX 编译为合理的 JavaScript),组件 API 只是通过添加 React Hooks 变得更简单,并且该框架为解决的核心 UI 问题提供非常少的抽象概念。

因此,学习 JavaScript 对于使用 React 有效构建应用程序是非常可取的。所以这里有一些 JavaScript 功能,我建议你花一些时间学习,这样你就可以尽可能有效地使用 React。

模板文字

模板文字就像具有超能力的字符串:

 1const greeting = 'Hello'
2const subject = 'World'
3console.log(`${greeting} ${subject}!`// Hello World!
4
5// this is the same as:
6console.log(greeting + ' ' + subject + '!')
7
8// in React:
9function Box({className, ...props}{
10  return <div className={`box ${className}`} {...props} />
11}
12

MDN:模板文字(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

简写属性名

很常见并且有用,我直到现在都没有想到可以这样做。

 1const a = 'hello'
2const b = 42
3const c = {d: [truefalse]}
4console.log({a, b, c})
5
6// this is the same as:
7console.log({a: a, b: b, c: c})
8
9// in React:
10function Counter({initialCount, step}{
11  const [count, setCount] = useCounter({initialCount, step})
12  return <button onClick={setCount}>{count}</button>
13}

MDN:ECMAScript 2015中对象初始化的新表示法(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015

箭头函数

箭头函数是在 JavaScript 中另一种编写函数的方法,但它们确实存在一些语义差异。幸运的是我们在 React 的土地上,如果在项目中使用hook(而不是类)就不必担心 this,但是箭头函数允许更复杂的匿名函数和隐式返回,所以你会看到并想要充分利用箭头的功能。

 1const getFive = () => 5
2const addFive = a => a + 5
3const divide = (a, b) => a / b
4
5// this is the same as:
6function getFive({
7  return 5
8}
9function addFive(a{
10  return a + 5
11}
12function divide(a, b{
13  return a / b
14}
15
16// in React:
17function TeddyBearList({teddyBears}{
18  return (
19    <ul>
20      {teddyBears.map(teddyBear => (
21        <li key={teddyBear.id}>
22          <span>{teddyBear.name}</span>
23        </li>
24      ))}
25    </ul>

26  )
27}

MDN:箭头函数(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

解构

解构可能是我最喜欢的 JavaScript 功能。我一直在构造对象和数组(如果你使用 useState,可能也是如此,就像这样【https://kentcdodds.com/blog/react-hooks-array-destructuring-fundamentals】)。我喜欢它的陈述性。

 1// const obj = {x: 3.6, y: 7.8}
2// makeCalculation(obj)
3
4function makeCalculation({x, y: d, z = 4}{
5  return Math.floor((x + d + z) / 3)
6}
7
8this is the same as
9function makeCalculation(obj{
10  const {x, y: d, z = 4} = obj
11  return Math.floor((x + d + z) / 3)
12}
13
14// which is the same as
15function makeCalculation(obj{
16  const x = obj.x
17  const d = obj.y
18  const z = obj.z === undefined ? 4 : obj.z
19  return Math.floor((x + d + z) / 3)
20}
21
22// in React:
23function UserGitHubImg({username = 'ghost', ...props}{
24  return <img src={`https://github.com/${username}.png`} {...props} />
25}
26

MDN:解构分配(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

一等要去阅读 MDN 文章,你肯定能够学到新东西。当你完成后,尝试用单行解构:

 1function nestedArrayAndObject({
2  // refactor this to a single line of destructuring...
3  const info = {
4    title'Once Upon a Time',
5    protagonist: {
6      name'Emma Swan',
7      enemies: [
8        {name'Regina Mills'title'Evil Queen'},
9        {name'Cora Mills'title'Queen of Hearts'},
10        {name'Peter Pan'title`The boy who wouldn't grow up`},
11        {name'Zelena'title'The Wicked Witch'},
12      ],
13    },
14  }
15  // const {} = info // <-- replace the next few `const` lines with this
16  const title = info.title
17  const protagonistName = info.protagonist.name
18  const enemy = info.protagonist.enemies[3]
19  const enemyTitle = enemy.title
20  const enemyName = enemy.name
21  return `${enemyName} (${enemyTitle}) is an enemy to ${protagonistName} in "${title}"`
22}

参数默认值

这是另一个我一直在用的功能:一种以声明方式表达函数默认值的非常强大的方法。

 1// add(1)
2// add(1, 2)
3function add(a, b = 0{
4  return a + b
5}
6
7// is the same as
8const add = (a, b = 0) => a + b
9
10// is the same as
11function add(a, b{
12  b = b === undefined ? 0 : b
13  return a + b
14}
15
16// in React:
17function useLocalStorageState({
18  key,
19  initialValue,
20  serialize = v => v,
21  deserialize = v => v,
22}
{
23  const [state, setState] = React.useState(
24    () => deserialize(window.localStorage.getItem(key)) || initialValue,
25  )
26
27  const serializedState = serialize(state)
28  React.useEffect(() => {
29    window.localStorage.setItem(key, serializedState)
30  }, [key, serializedState])
31
32  return [state, setState]
33}

MDN:默认参数(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters

Rest/Spread

...语法可以被认为是一种“集合”语法,它在一组值上运行。我一直都在使用,强烈建议你也学习。它实际上在不同的环境中有不同的含义,因此学习那些细微差别会对你有所帮助。

 1const arr = [56849]
2Math.max(...arr)
3// is the same as
4Math.max.apply(null, arr)
5
6const obj1 = {
7  a'a from obj1',
8  b'b from obj1',
9  c'c from obj1',
10  d: {
11    e'e from obj1',
12    f'f from obj1',
13  },
14}
15const obj2 = {
16  b'b from obj2',
17  c'c from obj2',
18  d: {
19    g'g from obj2',
20    h'g from obj2',
21  },
22}
23console.log({...obj1, ...obj2})
24// is the same as
25console.log(Object.assign({}, obj1, obj2))
26
27function add(first, ...rest{
28  return rest.reduce((sum, next) => sum + next, first)
29}
30// is the same as
31function add({
32  const first = arguments[0]
33  const rest = Array.from(arguments).slice(1)
34  return rest.reduce((sum, next) => sum + next, first)
35}
36
37// in React:
38function Box({className, ...restOfTheProps}{
39  const defaultProps = {
40    className`box ${className}`,
41    children'Empty box',
42  }
43  return <div {...defaultProps} {...restOfTheProps} />
44}
45

MDN:Spread语法(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax

MDN:Rest 参数(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

ESModules

如果你正在使用现代工具构建自己的程序,它应该能够支持模块,了解语法怎样工作是个好主意,因为所有的甚至微不足道的程序都可能需要使用模块来重用代码。

 1export default function add(a, b{
2  return a + b
3}
4
5/*
6 * import add from './add'
7 * console.assert(add(3, 2) === 5)
8 */

9
10export const foo = 'bar'
11
12/*
13 * import {foo} from './foo'
14 * console.assert(foo === 'bar')
15 */

16
17export function subtract(a, b{
18  return a - b
19}
20
21export const now = new Date()
22
23/*
24 * import {subtract, now} from './stuff'
25 * console.assert(subtract(4, 2) === 2)
26 * console.assert(now instanceof Date)
27 */

28
29// in React:
30import React, {Suspense, Fragment} from 'react'

MDN:import(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

MDN:export(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export

三元表达式

我喜欢三元表达式。他们的声明很漂亮。特别是在 JSX 中。

 1const message = bottle.fullOfSoda
2  ? 'The bottle has soda!'
3  : 'The bottle may not have soda :-('
4
5// is the same as
6let message
7if (bottle.fullOfSoda) {
8  message = 'The bottle has soda!'
9else {
10  message = 'The bottle may not have soda :-('
11}
12
13// in React:
14function TeddyBearList({teddyBears}{
15  return (
16    <React.Fragment>
17      {teddyBears.length ? (
18        <ul>
19          {teddyBears.map(teddyBear => (
20            <li key={teddyBear.id}>
21              <span>{teddyBear.name}</span>
22            </li>
23          ))}
24        </ul>
25      ) : (
26        <div>There are no teddy bears. The sadness.</div>
27      )}
28    </React.Fragment>
29  )
30}
31

我意识到,在 prettier 出现并清理我们的代码之前,一些人不得不花时间弄清楚三元运算符是怎么回事,这让三元表达式变得令人反感。如果你还没有使用 prettier,我强烈建议你这样做。prettier 将使你的三元表达式更容易阅读。

MDN:条件(三元)运算符(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator

数组方法

数组很棒,我一直使用数组方法!以下是我常用的方法:

  • find

  • some

  • every

  • includes

  • map

  • filter

  • reduce

这里有些例子:

 1const dogs = [
2  {
3    id'dog-1',
4    name'Poodle',
5    temperament: [
6      'Intelligent',
7      'Active',
8      'Alert',
9      'Faithful',
10      'Trainable',
11      'Instinctual',
12    ],
13  },
14  {
15    id'dog-2',
16    name'Bernese Mountain Dog',
17    temperament: ['Affectionate''Intelligent''Loyal''Faithful'],
18  },
19  {
20    id'dog-3',
21    name'Labrador Retriever',
22    temperament: [
23      'Intelligent',
24      'Even Tempered',
25      'Kind',
26      'Agile',
27      'Outgoing',
28      'Trusting',
29      'Gentle',
30    ],
31  },
32]
33
34dogs.find(dog => dog.name === 'Bernese Mountain Dog')
35// {id: 'dog-2', name: 'Bernese Mountain Dog', ...etc}
36
37dogs.some(dog => dog.temperament.includes('Aggressive'))
38// false
39
40dogs.some(dog => dog.temperament.includes('Trusting'))
41// true
42
43dogs.every(dog => dog.temperament.includes('Trusting'))
44// false
45
46dogs.every(dog => dog.temperament.includes('Intelligent'))
47// true
48
49dogs.map(dog => dog.name)
50// ['Poodle', 'Bernese Mountain Dog', 'Labrador Retriever']
51
52dogs.filter(dog => dog.temperament.includes('Faithful'))
53// [{id: 'dog-1', ..etc}, {id: 'dog-2', ...etc}]
54
55dogs.reduce((allTemperaments, dog) => {
56  return [...allTemperaments, ...dog.temperaments]
57}, [])
58// [ 'Intelligent', 'Active', 'Alert', ...etc ]
59
60// in React:
61function RepositoryList({repositories, owner}{
62  return (
63    <ul>
64      {repositories
65        .filter(repo => repo.owner === owner)
66        .map(repo => (
67          <li key={repo.id}>{repo.name}</li>
68        ))}
69    </ul>

70  )
71}

MDN:Array(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array

Promises 和 async/await

这是一个很大的主题,可以在它们身上多花一些时间。Promises 在 JavaScript 生态中无处不在,并且由于 React在该生态系统中的根深蒂固,它们几乎到处都是(事实上,React 本身在内部也在使用 promises)。

Promises 可帮助你管理异步代码。Async/await 语法是处理 promises 的特殊语法。这两者是相辅相成的。

 1function promises({
2  const successfulPromise = timeout(100).then(result => `success: ${result}`)
3
4  const failingPromise = timeout(200true).then(null, error =>
5    Promise.reject(`failure: ${error}`),
6  )
7
8  const recoveredPromise = timeout(300true).then(null, error =>
9    Promise.resolve(`failed and recovered: ${error}`),
10  )
11
12  successfulPromise.then(log, logError)
13  failingPromise.then(log, logError)
14  recoveredPromise.then(log, logError)
15}
16
17function asyncAwaits({
18  async function successfulAsyncAwait({
19    const result = await timeout(100)
20    return `success: ${result}`
21  }
22
23  async function failedAsyncAwait({
24    const result = await timeout(200true)
25    return `failed: ${result}`
26  }
27
28  async function recoveredAsyncAwait({
29    let result
30    try {
31      result = await timeout(300true)
32      return `failed: ${result}` // this would not be executed
33    } catch (error) {
34      return `failed and recovered: ${error}`
35    }
36  }
37
38  successfulAsyncAwait().then(log, logError)
39  failedAsyncAwait().then(log, logError)
40  recoveredAsyncAwait().then(log, logError)
41}
42
43function log(...args{
44  console.log(...args)
45}
46
47function logError(...args{
48  console.error(...args)
49}
50
51// This is the mothership of all things asynchronous
52function timeout(duration = 0, shouldReject = false{
53  return new Promise((resolve, reject) => {
54    setTimeout(() => {
55      if (shouldReject) {
56        reject(`rejected after ${duration}ms`)
57      } else {
58        resolve(`resolved after ${duration}ms`)
59      }
60    }, duration)
61  })
62}
63
64// in React:
65function GetGreetingForSubject({subject}{
66  const [isLoading, setIsLoading] = React.useState(false)
67  const [error, setError] = React.useState(null)
68  const [greeting, setGreeting] = React.useState(null)
69
70  React.useEffect(() => {
71    async function fetchGreeting({
72      try {
73        const response = await window.fetch('https://example.com/api/greeting')
74        const data = await response.json()
75        setGreeting(data.greeting)
76      } catch (error) {
77        setError(error)
78      } finally {
79        setIsLoading(false)
80      }
81    }
82    setIsLoading(true)
83    fetchGreeting()
84  }, [])
85
86  return isLoading ? (
87    'loading...'
88  ) : error ? (
89    'ERROR!'
90  ) : greeting ? (
91    <div>
92      {greeting} {subject}
93    </div>

94  ) : null
95}

MDN:Promise(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

MDN:async function(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

MDN:await(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

结论

当然有许多语言功能在构建 React 应用时很有用,这些是我最喜欢的,我发现自己一次又一次地使用它们。希望对你有帮助。

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

 图片

下面夹杂一些私货:也许你和高薪之间只差这一张图

2019年京程一灯课程体系上新,这是我们第一次将全部课程列表对外开放。

愿你有个好前程,愿你月薪30K。我们是认真的 !图片


图片

在公众号内回复“体系”查看高清大图

长按二维码,加大鹏老师微信好友

拉你加入前端技术交流群

唠一唠怎样才能拿高薪

图片

图片


 往期精选 

小手一抖,资料全有。长按二维码关注前端先锋,阅读更多技术文章和业界动态。

图片

12250使用 React 要懂的 JavaScript 特性[每日前端夜话0xB3]

root

这个人很懒,什么都没留下

文章评论