React起手式

大纲链接 §

[toc]


如何入门 React

  • 写一个 Hello World,写一个 +1,写一个 ToDo
  • 把文档过一遍
    • 组件
    • 父子组件通信
    • 组件生命周期 使用Hooks API模拟
    • Context API 怎么用
    • Hooks API 怎么用
    • useState
    • useEffect
    • CSS in JS
      • styled-component 怎么写,有什么优缺点
      • css modules 怎么写,有什么优缺点
    • React Router 怎么用
    • Redux 怎么用
      • action 怎么触发(用什么 API,什么是 payload,具体代码是什么)
      • reducer 怎么用 state 和 action 得到新的 state(要不要深拷贝,代码是什么)
      • state 变化后页面怎么更新(Provider 组件的使用)
      • 如何从 state 中得到某个数据(Connect 函数的使用)

开源项目实践

  • 模仿Win11 系统有很多小组件,比如 win11 desktop by blueedge
    • 计算器
    • 画图
    • 记事本
    • 扫雷
  • 造轮子,搭建管理工具
  • 写一个极简的记账App

1. 如何引入 React

有两种方式

  • CDN
  • import

CDN 引入 React

  • React相较于Vue可直接中CDN引入链接而言,更加复杂
  • CDN 引入(顺序不可颠倒),这里是一个codesandbox例子
    • 引入 Reacthttps://.../react.x.min.js
    • 引入 ReactDOMhttps://.../react-dom.x.min.js
  • 不在项目中使用 CDN 引入方式
    • babel转义耗时与代码量成正比,不适合在项目中使用
    • 无法较方便地做版本处理,需要使用 import 的方式

cjsumd 的区别

  • 搜索 BootCDN ,查看 React 的版本分为 cjsumd
  • cjs 全称 CommonJS,是 Node.js 支持的模块规范
  • umd 是统一模块定义,兼容各种模块规范(包含浏览器)
  • 理论上优先使用 umd,同时支持 Node.js 和浏览器
  • 最新的模块规范 ESMECMA Script Modules) 是使用 importexport 关键字,是官方标准的规范,推荐使用
  • 模块化方面,官方规范优于社区实现,推荐优先使用
    • cjsumd 是社区实现的规范,是一种事实规范
    • js 生态中不一定以官方规范为准,还要考虑社区的实现,结合主流流行的解决方案选择技术

工程化地引入 React ,通过webpackVite等打包工具

环境搭建

  • Node 16+
  • npm 8+ 推荐 pnpm 7+(或 yarn3+
  • IDE使用VSCodewebStorm
  • 终端推荐 cmder(for win)或 item2(for macOS),或者基本使用(Git Bash
  • 版本管理 git + github
  • JS 版本 ES6+,CSS 病本CSS3+
    • typescript 版本 4.8+sass版本1.55+

安装

1
2
pnpm add react react-dom
# yarn add react react-dom

引入 import...from...

1
2
import React from 'react'
import ReactDOM from 'react-dom'
  • 注意大小写,约定俗成,保持一致
    • 模块变量名 ReactReactDOM 注意大写的字母
    • 仓库名 reactreact-dom 小写

其他

  • 除了 webpackVite 以外,rollupparcel也支持以上写法,作用是将浏览器不支持的js转移成支持的 js版本

新项目使用 Vite,老项目使用 create-react-appwebpackrollup

使用官方推荐的脚手架 create-react-app

安装

1
pnpm add -g create-react-app

使用 create-react-app

1
2
3
4
5
6
7
# 进入项目目录 创建应用
create-react-app react-demo-0

# 或者创建目录
# mkdir react-demo-1
# cd react-demo-1
# create-react-app .
  • 自动安装相关依赖
  • 安装过程中,无须关注黄色警告,只要没有报错就是安装成功了

运行应用

1
2
cd react-demo-0
pnpm start
  • 自动打开网页,访问 localhost:3000

将 IDE 安装目录的bin文件 添加到系统环境变量,以win11为例

  • Win + R 打开 运行,输入 sysdm.cpl,回车,新建目录即可
  • 启动 VSCodeWebStorm
1
2
# 打开当前目录
webstorm64.exe .

方便使用,在~/.bashrc中设置别名

1
alias ws="webstorm64"
  • 在命令行中运行 source ~/.bashrc 即可生效

使用 VSCodeWebStorm 打开项目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 打开目录 win
start .

# 打开目录 mac
open .

# 直接用 VSCode 打开
code .

# 直接用 WebStorm 打开
ws .

也可以自己封装脚手架,或使用其他开源的 React 脚手架

缺点:构建太慢

  • 解决:使用 Vite

使用 Vite 搭建 §

使用 PNPM 搭建一个 ViteReact 项目

1
pnpm create vite react-demo-1 --template react-ts

进入项目 安装依赖 运行项目

1
2
3
cd react-demo-1
pnpm install
pnpm run dev

简化运行命令 设置别名 pd for pnpm run dev

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "react-demo-1",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "pd": "pnpm run dev",
    "build": "tsc && vite build",
    "pb": "pnpm run build",
    "preview": "vite preview",
    "pv": "pnpm run preview"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/react": "18.0.21",
    "@types/react-dom": "18.0.6",
    "@vitejs/plugin-react": "2.1.0",
    "typescript": "4.8.3",
    "vite": "3.1.3"
  }
}

参考


最小化配置与新旧版本的区别写法

  • 删除多余 文件 如自动生成的 index.cssApp.cssApp.test.jssetupTest.jsserviceWorker.jslogo.svgApp.tsx

查看入口文件 main.tsx

1
2
3
4
5
6
7
8
import React from 'react'
import ReactDOM from 'react-dom/client'
// import App from './App' // 删除
// import './index.css' // 删除

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<div>Hi</div>)

// ReactDOM.render(<div>Hi</div>, document.getElementById('root'))

先不使用组件 App.tsx

  • 挂载根组件写法
    • React17-的挂载根组件写法:ReactDOM.render(<App />, rootElement);
    • React18+的挂载根组件写法:ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(<div>Hi</div>)
  • ReactDOM的引入路径
    • React17-的引入路径:import ReactDOM from 'react-dom';
    • React18+的引入路径:import ReactDOM from 'react-dom/client';
  • 最小化实现应用启动,稍后介绍组件化

参考


2. React 初体验

2.1 用React 实现 +1

现在codesandbox中尝试,从最原始的 HTML开始,展示一个红色的 n

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="src/index.css" />
  </head>
  <body>
    <div id="root"></div>
    <script src="https://cdn.bootcss.com/react/16.10.2/umd/react.development.js"></script>
    <script src="https://cdn.bootcss.com/react-dom/16.10.2/umd/react-dom.development.js"></script>
    <script src="src/index.js"></script>
  </body>
</html>

index.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
 *
console.log(window.React);
console.log(window.React.createElement);
console.log(window.ReactDOM);
console.log(window.ReactDOM.render);
 *
 * */

const React = window.React;
const ReactDOM = window.ReactDOM;
const root = document.getElementById("root");

let n = 0;
const App = React.createElement("div", { className: "red" }, [
  n,
  React.createElement(
    "button",
    {
      onClick: () => {
        n += 1;
        console.log(n); //这一句是精髓
        ReactDOM.render(App, root); // 为什么还是不能重新渲染
      }
    },
    "+1"
  )
]);
// React 17-
ReactDOM.render(App, root);
  • 获取 #root 节点 const root = document.getElementById("root");
  • 使用 const App = React.createElement(tag, {}, Node) 创建 React 元素
  • 使用 ReactDOM.render(App, root)React 元素渲染页面

查看失败的例子

  • React不会根据用户操作,自动刷新视图,需要执行去刷新
  • 失败的原因,靠JS的基础知识来判断
    • 失败是因为 const App = React.create...,赋值的右侧代码 只执行一次
  • 如何让它重新执行,以获取n的最新值:
    • 外层包装一层函数,使用函数来返回结果,每次执行,就会得到新的结果,即 工厂模式
    • const App = () => React.createElement()
    • ReactDOM.render(App(), root); 渲染的是 执行工厂函数返回的 React 元素
    • 再次执行 ReactDOM.render(App(), root);
  • 函数执行时,会重新去读取一次 n 的 值,所以 n 更新了,页面也会更新
    • 函数会获取变量的最新值
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// ...
let n = 0;
const App = () => React.createElement("div", { className: "red" }, [
  n,
  React.createElement(
    "button",
    {
      onClick: () => {
        n += 1;
        console.log(n);
        ReactDOM.render(App(), root);
      }
    },
    "+1"
  )
]);
// React 17-
ReactDOM.render(App(), root);
  • 通常称
    • React.createElement() 返回结果 为 React 元素
    • const App = () => React.createElement()React 函数组件

JS基础复习:打印6个6面试题

以一个 "打印6个6" 的经典例子,来说明函数可以获取最新值

1
2
3
4
5
6
let i // 外部作用域
for(i = 0; i < 6; i++) {
  setTimeout(() => {
    console.log(i)
  }, 1000)
}
  • 代码的结果是一秒钟后打印 6 个 6,因为 函数执行时遇到外部变量会读取其最新值
  • 注意 setTimeout(()=>void, 0) 并不代表0s后立即执行回调函数
  • setTimeout 的作用是 在给定时间倒计时完成后,将回调放入 任务 Task 队列中,浏览器的 JS 引擎处理事件循环的一种机制
    • ① 先将调用栈中同步代码执行完后
    • ② 调用微任务队列中所有的函数来执行
    • ③ 再去取出一个 任务 Task 队列首部的函数来执行
    • 以后一直按照 ① -> ② -> ③ 再回到 ① 的顺序 执行代码,直到调用栈被全部清空
  • 在循环语句中,有6次同步执行setTimout定时器,即有6次将回调函数推入 任务队列
    • 期间 外部作用域中变量i的值,执行同步代码已累加到6,而队列中的函数由于未执行,没有在此时 访问变量i
    • 执行完同步代码,每次取出一个 任务队列中的 回调执行,打印i,此时i的值 为6
  • 如何按预期打印1-5
    • 使用 函数作用域 立即执行函数 立即传入参数i
      • for(i=0; i<6; i++) { ( (j)=>void )(i) }
        • 实参i,形参j
      • 实参和形参可同名
        • for(i=0; i<6; i++) { ( (i)=>void )(i) }
    • 使用 块级作用域 循环每次 在作用域内部用 let 声明变量 (创建一个新的 块级作用域中的独立变量),不受外部作用域影响,缓存每次循环的i值,而不是被销毁
      • for(let i = 0; i < 5; i++) {/* 将循环体代码块中的 let 放到循环表达式中 */}(这是ES6语法糖)
      • 而外层作用域中无法访问到i
  • 所以最初的代码失败可以 通过将APP变为函数来解决

题外话

  • React会促使我们思考函数的本质

3. 函数的本质——延迟执行逻辑

对比普通代码 与函数

  • 普通代码 let b = 1 + a
  • 函数(不讨论参数)
    • let f = () => 1 + a
    • let b = f()

可以看出

  • 普通代码 运行时 立即求值,读取变量的 a 的当前值
  • 函数会等调用时,在访问变量求值,即 延迟求值
    • 并且 求值时才会读取 a最新值

对比 React 元素 和 React 函数组件

  • const App1 = React.createElement('div', null, n) 是一个 React 元素
  • const App2 = () => React.createElement('div', null, n) 是一个 React 函数组件

启示

  • 元素 App1 会立即获取n的值
  • 函数 App2延迟执行 的代码,会在 被调用时 才获取
    • n变化了,再次调用 App2() 就可以得到最新的数据,从而渲染为最新的视图
  • 注意是 代码执行时机, 区别于同步 和 异步
    • 同步 和 异步 关注的是 得到结果的时机

4. 小结

目前已了解了

  • React 元素
    • React.createElement() 的返回值 element 可以代表一个 div
    • element 并不是真正的 div,不能直接插入到页面中 (DOM对象)
    • 一般称 element虚拟DOM对象
      • 包含 标签名、属性名和子节点
  • () => React元素,即 React 函数组件
    • 返回 element 的函数,也可以代表一个 div
    • 这个函数可以 多次执行,每次得到最新的 虚拟 div
    • React 会对比两个虚拟 div找出不同,局部更新视图,而不是整体低效地替换

使用调式来 验证 React 局部更新视图

  • 运行项目,查看浏览器控制台,当点击 +1 时,并没有替换掉 button 只是替换了 n 的值
  • 找出不同部分 的算法 称为 DOM Diff 算法

可是至此 React 的代码很丑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
const React = window.React;
const ReactDOM = window.ReactDOM;

let n = 0;
const App = () =>
  React.createElement("div", null, [
    n,
    React.createElement(
      "button",
      {
        onClick: () => {
          n += 1;
          console.log(n);
          ReactDOM.render(App(), document.querySelector("#app"));
        }
      },
      "+1"
    )
  ]);

ReactDOM.render(App(), document.querySelector("#app"));
  • VueSFC 写法复杂多了
  • 可用 JSX 经过处理后可实现:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react";
import ReactDOM from "react-dom";

let n = 0;
const App = () => (
  <div>
    {n}
    <button onClick={add}>+1</button>
  </div>
);

const render = () => ReactDOM.render(
  <App />,
  document.getElementById("root")
);

const add = () => {
  n += 1;
  render();
};

render();

5. JSX 初体验

JSX中的 X 表示扩展,所以 JSX 就是 JS 的 扩展版

  • 对比 Vue 中 有 vue-loader
    • .vue 文件里写 <template><script><style>
    • 通过 vue-loader 变成一个构造选项
  • ReactJSX
    • <button onClick="add">+1</button>
    • 变成 React.createElement('button', {onClick:...}, '+1')
    • 这其中用到了 编译原理
    • 无需使用 已废弃的 jsx-loader,它已被 babel-loader 取代了
    • babel-loaderwebpack 内置了
    • vue-loader 未被 webpack 内置,所以相对而言配置 React 更简单
      • Vue 的作者和 webpack 关系不够强,所以没有得到 webpack 的支持
  • Vue 也可以通过插件来支持 JSX

使用 JSX

方法一:CDN

  • 引入 babel.min.js
  • <script> 改成 <script type="text/babel">
  • babel会自动进行转译:
    • 引入 <script src="babel.js"></script>
    • 浏览器 无法识别 HTML<script type="text/babel"> 内容,不执行脚本
    • babel.js 会获取到 <script type="text/babel">中的代码,将其转译后得到新的字符串(即转移后的JS代码字符串)
    • babel.js 将这段字符串放到一个新的 <script> 标签中
    • babel.js 将这个 <script> 标签替换掉 之前的 <script type="text/babel"> 删除 type="text/babel"
      • 即转译为 浏览器可识别的JS脚本代码,之后执行
  • 这种方式并不支持 src,请看实例
  • 忠告:
    • 永远不要在生产环境中使用方法一,因为效率太低,不适合工程化
    • 它需要额外下载一个 babel.min.js
    • 它还需要在浏览器端把JSX转译为JS
  • 更加工程化的做法是在 build时转译,见之后的方法

方法二:webpack + babel-loader

  • 不适合新手,跳过,直接用方法三

方法三:create-react-app

  • @vue/cli 用法相似,使用命令行
    • 全局安装 pnpm add -g create-react-app
    • 初始化目录 create-react-app <Project-Name>
    • 进入目录 cd <Project-Name>
  • 使用最小知识原则
    • src 目录只留下两个文件
    • 将除 public/index.html 外的多余文件删掉
  • 启动项目
    • 运行 pnpm start
  • 声明一个函数组件 App.jsx
    • const App = () => (<div>Hi</div>)
    • export default App
  • index.js 中 引入 import App from './App'
    • ReactDOM.render(<App />, document.getElementById('root'))
  • create-react-app会把 .js 文件默认 看做 .jsx 文件
  • 查看 App 是否默认使用 jsx 语法
    • 因为 webpackJS默认走 babel-loader
  • JSX 中的 <App /> 就相当于 React.createElement()
    • 必须引入 import React from 'react' 防止报错

方法四:Vite + @vitejs/plugin-react

  • 更快速地启动项目,使用esbuild 0打包运行项目
  • 详见 使用 Vite 搭建

使用 JSX 的注意事项

  • 注意 className 属性
    • <div className="red">n</div>被转译为
    • React.createElement('div', {className: 'red'}, 'n')
    • 而不能直接使用 class 属性,因为在JS中是使用 className来获取或设置指定元素的 class 属性的值
    • MDN Element.className
  • 插入变量
    • 标签中的所有JS代码都需要用 {} 括起来
      • 如果使用变量n,就用{}n 包起来,如 {n}
      • 如果使用对象,就用{}将对象包起来,如 { {name: 'xxx'} }
  • 使用函数 <button onClick={ () => {} }></button>
  • 习惯 return 后面加上 {},即 return ()
    • 不加相当于 return undefined 报错

现在 VueReact 势均力敌

  • 都可以写 HTML
    • Vue 写在 .vue 文件的 <template>
    • ReactHTML 混在 JS/JSX 文件里

6. 如何使用条件判断与循环控制

6.1 条件判断

Vue

1
2
3
4
5
6
<template>
  <div>
    <div v-if="n%2===0">n是偶数</div>
    <span v-else>n是奇数</span>
  </div>
</template>

JSX 的条件判断,React

  • JSX将标签也当做类似对象的东西使用,直接交给内置的babel-loader去转译
    • 标签中的JS代码必须加花括号,否则转译为字符串
  • React中,一切皆JS
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
const Component = () => {
  return (
    n%2 === 0
      ? <div>n是偶数</div>
      : <span>n是奇数</span>
    )
}

// 如果需要外面的 div,可以写成
const Component2 = () => {
  return (
    <div>
      {
        n%2 === 0
          ? <div>n是偶数</div>
          : <span>n是奇数</span>
      }
    </div>
    )
}

// 也可以声明变量
const Component3 = () => {
  const content = (
    <div>{
      n%2 === 0
        ? <div>n是偶数</div>
        : <span>n是奇数</span>
    }</div>
  )
  return content
}

// 单独提出三元表达式
const Component4 = () => {
  const inner = n%2 === 0
    ? <div>n是偶数</div>
    : <span>n是奇数</span>
  const content = (
    <div>
      { inner }
    </div>
  )
  return content
}

// 直接使用 JS 的条件语句
const Component5 = () => {
  let inner
  if(n%2 === 0) {
    inner = <div>n是偶数</div>
  } else {
    inner = <span>n是奇数</span>
  }
  const content = (
    <div>
      { inner }
    </div>
  )
  return content
}

// 使用多行注释
const Component6 = () => {
  return (
    <div>Hi
    {/*
      {
        n%2 === 0
          ? <div>n是偶数</div>
          : <span>n是奇数</span>
      }
    */}
    </div>
  )
}
  • React 中通常使用 三元表达式 来处理条件判断
    • 可以提取出外部的 div,在里面写逻辑,返回虚拟节点
    • 可以声明变量,来复用虚拟节点
    • 可以单独提取出三元表达式的逻辑,赋值给变量来复用
    • 甚至直接使用 JSif条件语句
  • 使用 {/* {...} */} 来表示多行注释,将花括号中的代码注释起来

结论

  • VueSFC 中,只能 Vue 提供的语法写条件判断
  • ReactJSX 中则更加灵活,只是在写JS而已
  • Vue 中也可以使用 JSX,配合 Vue 的指令、响应式方法也可以做到像 React 那样灵活

6.2 循环控制

Vue 里可以使用v-for遍历数组和对象

1
2
3
4
5
6
7
<template>
  <div>
    <div v-for="(item, index) in numbers" :key="item.id">
      下标 {{index}},值为 {{n}} 
    </div>
  </div>
</template>

React 中,通过 props 参数可以遍历数组和对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
const Component = (props) => {
  return props.numbers.map( (item, index) => {
    return (<div key={item.id}>下标 {index} 值为 {item}</div>)
  })
}

// 如果需要外面的 div,可写成
const Component = (props) => {
  return (
    <div>
      {
        props.numbers.map( (item, index) => {
          return (
            <div key={item.id}>下标 {index} 值为 {n}</div>
          )
        })
      }
    </div>
  )
}
  • React 中主要使用 map 来处理循环逻辑,遍历数组数据
    • 甚至可以直接使用for循环,但不如map来得简洁
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react'
const Component = (props) => {
  const array = []
  for(let i = 0; i < props.numbers.length; i++) {
    array.push(
      <div key={i}>
        下标 {i} 值为 {props.numbers[i]}
      </div>
    )
  }
  return (<div>{array}</div>)
}

// 使用组件
const App = () => {
  return (
    <div>
      App 组件
      <Component number={ [1, 2, 3] } />
    </div>
  )
}

Vue SFCReact 的区别凸显

  • Vue SFC封装的v-* 更适合新人
  • React 更适合JS基础查实的开发者
  • 两个框架提供的封装程度不同而已,思想差别并不是很大

7. React 起手总结

目前已经学了

  • 引入 ReactReactDOM
    • 工程化安装引入 import React from 'react'
  • React.createEelement
    • 创建虚拟 DOM 对象
    • 函数的作用:多次创建虚拟 DOM 对象
    • 初步了解DOM Diff
  • JSX
    • XML 转译为 React.createElement
    • 使用 {} 插入 JS 代码
    • create-react-app 默认将JS 当做 JSX 处理
    • 条件判断、循环要用原生JS语法实现

8. 测试 React 初体验

写出功能,要求:点+1后,数字会+1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react";
import ReactDOM from "react-dom";

let n = 0;
const root = document.getElementById("root")
const button = <button onClick={add}> +1 </button>

const App = () => (
  <div>
    {n}
    {button}
  </div>
);

const render = () => ReactDOM.render(<App />, root);

const add = () => {
  n += 1;
  render();
};

render();
  • 关于 ReactReactDOM,必须同时使用这两个库才能在浏览器上开发 React 应用
  • 关于 const x = React.createElement('div', null, 'hi')x 是一个 React 元素,它代表一个 div,它是一个虚拟 DOM 对象
  • return 后面有括号()JS表达式 用 {} 括起

假设页面中已经有一个 id 为 root 的 div,我希望把 <h1>Hello, world!</h1> 展示在页面里,代码如下

1
2
3
4
________A________(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);
  • 请问 A 出应该填写什么?答案为 15 个字符:ReactDOM.render

代码

1
2
3
4
function ComponentA(){
    return
      <div>hi</div>
}
  • 请问 ComponentA() 的返回值是:
    • undefined
    • 一个 React 元素,对应一个 div

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
function ComponentA(props){
    return(
        <div style=_______B________>hi</div>
    )
}

function App(){
    return (
        <div>
            <ComponentA width={100}/>
        </div>
    )
}
  • 需求是让 ComponentA 的 div 的宽度与 props.width 一致,请问 _____B______ 处应该怎么填?
  • 代码运行处:https://codesandbox.io/s/01z20q1p8w
  • 答:{{width:`${props.width}px`}} 参考:https://codesandbox.io/s/lively-tdd-5mr7iq

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function ComponentA(props){
    const {children, ...rest} = props
    return(
        <div>
            <div> A 组件</div>
            <ComponentB ______C______/>
        </div>
    )
}

function ComponentB(props){
    console.log(props)  // 注意这里
    return(
        <div>
            <div> B 组件</div>
        </div>
    )
}

function App(){
    return (
        <div>
            <ComponentA width={100} height={100} other={404}>
              A
            </ComponentA>
        </div>
    )
}

  • 需求是让 ComponentA 把自己接收到的所有属性都传递给 ComponentB,请问 _____C______ 处应该怎么填?
  • 也就是说代码中的 console.log(props) 必须只打印出 {width: 100, height: 100, other: 404}
  • 代码运行处:https://codesandbox.io/s/z6q431v44l
  • 选项
    • props
    • rest
    • ...props
    • ...rest
    • {...props}
    • {...rest}
  • 答案:https://codesandbox.io/s/cranky-cerf-8jvx1v

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function log(x) {
  console.log(x);
}

function App() {
  return (
    <div>
      <button onClick={____1____}>1</button>
      <button onClick={____2____}>2</button>
    </div>
  );
}
  • 需求是点击 button 1 就调用 log(1),点击 button 2 就调用 log(2),请问 _____1_____ 处应该怎么填?(只填1处不填2处)
  • 代码运行处:https://codesandbox.io/s/qqkn530q4w
  • 选项
    • log(1)
    • ()=>log(1)

下面代码的输出结果是什么?(请用大脑推断,不要借助控制台来运行,下同)

1
2
3
Promise.reject('error')
    .then( ()=>{console.log('success1')}, ()=>{console.log('error1')} )
    .then( ()=>{console.log('success2')}, ()=>{console.log('error2')} )
  • 选项
    • 先输出 ‘error1’ 再输出 ‘error2’
    • 先输出 ‘error1’ 再输出 ‘success2’
    • 先输出 ‘success1’ 再输出 ‘success2’
    • 先输出 ‘success1’ 再输出 ‘error2’

下面代码的输出结果是什么?

1
2
3
4
5
6
7
8
function getSomething(){
    setTimeout(function(){
        return 'hello'
    })
}

let something = getSomething()
console.log(something)
  • 选项
    • ‘hello’
    • timer 的 id
    • undefined

下面代码的输出结果是什么?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
let _name = 'MyName'
let obj = {}
Object.defineProperty(obj, 'name', {
    get(){
        return _name
    },
    set(value){
        _name = value
    }
})

obj.name = 'NewName'
console.log(_name)
  • 选项
    • ‘MyName’
    • ‘NewName’
    • undefined


参考文章

相关文章


  • 作者: Joel
  • 文章链接:
  • 版权声明
  • 非自由转载-非商用-非衍生-保持署名