扬帆起航

注:本章节的 demo 都以类组件 + TS为例 等下一章 hook 章节后都为函数式组件

UI 库 统一使用 antd https://ant.design/components/overview-cn/

本节的所有代码都在这个 👉仓库

初始化项目

使用 webpack

npx create-react-app my-app --template typescript

# or

yarn create react-app my-app --template typescript

使用 vite

npm init vite@latest my-vue-app -- --template react-ts

# or

yarn create vite my-vue-app --template react-ts

配置可以参考 👉仓库 🏠

如果你暂时还不需要集成 typescript 的话 可以去掉 --template typescript

父子组件通信

父组件 --> 子组件

父 --> 子 比较简单

父组件直接通过 props 来传递属性

类组件用this.props.[属性名]即可拿到对应的属性

函数式组件直接使用props.[属性名]即可

子组件 --> 父组件

原理和 父 --> 子 类似

在父组件用 props 向子组件传递一个函数

然后在子组件用this.props.<函数名>触发这个函数

以下是一个计数器累加的 🌰

父组件负责管理数据和方法

下面是组件间的通信

父组件向子组件传递 count 变量

子组件触发父组件 累加方法

如果你执行上述代码的话 你会发现数据可以正常显示 这说明父组件的数据正确的传递给了子组件

但是一旦点击了按钮 页面就会报错 你会看到如下报错信息

TypeError: Cannot read property 'setState' of undefined

也就是 this 是 undefined

在上一讲我们就说到 在类组件中绑定事件时要注意 this 的绑定

React 并没有帮我们绑定 this 如果我们没有手动绑定 那么它就是 undefined

关于 React 为什么没有帮我们绑定 this 你可以戳 👉这篇文章

解决的方法有两种

  1. 手动绑定 this 在父组件的构造函数处 手动绑定为方法 绑定 this

  1. 使用箭头函数

生命周期函数

主要参考官方的生命周期图谱

具体有关生命周期的内容 我会在下几章中更新

这里 我只提最常用的几个生命周期函数以及它们的用途

  • constructor

    • 初始化内部的 state

    • 为事件绑定 this

  • render

    • React 的灵魂 用于描述 UI 和交互

    • props/state/forceUpdate 都会重新调用该生命周期 从而使页面更新

  • shouldComponentUpdate

    • 对比更新前后数据 优化性能

  • componentDidMount

    • 网络请求

  • componentWillUnmount

    • 清除定时器等 优化性能

状态提升

状态提升是一个概念性的东西

状态指 组件间共享的一些数据

提升指 将这些状态保存在离它们最近的父组件

比如更改主题 我们就需要将主题这个状态存放在根组件下 然后通过 props 一层一层往下传递

ref

我们实现一个简单实现一个 input 的功能

其内部数据由我们的 state 来维护

所以我们直接读 state 的值就是 input 中的值

现在我们直接通过 dom 去获取 input 的值

React 给我们提供了 ref 属性 通过这个属性 我们可以获取到元素的实例

两者的区别是

  • 前者 其实例在 current 属性下

  • 而通过函数创建 其实例就是我们所命名的那个属性

写在最后 在生产环境中 千万不要这样去操作 dom

所有可以使用声明式完成的功能都不要使用命令式

除非我们需要实现 聚焦 动画 等 必须要获取到 dom 的操作

受控组件/非受控组件

受控组件和非受控组件一般都是针对表单元素来说的 因为它们有自己的 value 属性 可以管理自己的状态

受控的意思是指元素的状态由外部数据来维护 可理解为数据驱动视图 就是上述例子中的前者

非受控的意思是指元素的状态由自己来维护 可理解为 jq 操作 dom 来拿数据 就是上述例子中通过 ref 来操作

context

假设 我们有一个 App 组件

然后 App 组件下有一个 HeaderWrapper 组件

HeaderWrapper 组件内部 又有一个 Header 组件

那么 如果我们想把 App 组件中的数据 到 Header 组件

数据流就要经过 HeaderWrapper 这个组件

但是这个组件是不需要 Header 组件需要的那个 props 的

尤其是当你使用了类型约束时 你会需要为传递数据的中间组件 编写它们不需要的 props 约束 😳

如果我们层层传递 那么代码如下

好吧 这只是经过了一层 我们已经感觉到了麻烦 如果是 🤔

这时 React 给我们提供了一个属性 context 用来解决跨组件通信的问题

常用 API 有

  • React.createContext(defaultValue)

  • contextType

  • Provider

  • Consumer

但是 在实际开发中 我们一般不会使用 context

在生成环境下 我们一般会使用 redux / mobx

有关 context 的发展历程 你可以看 👉这里

合成事件

React 中的绑定事件 onClick 等等 是 React 中的合成事件

它和原生的 onclick 事件 不同 主要是用于抹平各浏览器之间的差异

因为 React 不只是期望运行在 Web 环境 也期望运行在客户端 ios Android 等

在绑定事件时 传入的第一个参数默认就是 React 中的 event 对象

同样的 React 也封装了这个对象 为了适合所有开发场景下的使用

dangerouslySetInnerHTML

假设有以下代码 我们想要渲染出 tag 中的 dom 元素

直接渲染的话 它会被当成字符串 渲染在页面上

我们需要使用 dangerouslySetInnerHTML 告诉 React 这是一个 dom 元素

但是也存在副作用 正如它的名字 dangerously 一样

不合时宜的使用 可能会你的页面遭受 XSS 攻击

所以忘掉这个属性吧 😛

Fragments

所有的 JSX 必须要有一个根元素包裹

如果你不想创建额外的元素 那么你就可以使用 Fragments 来包裹它们

该元素不会创建任何额外的 dom 节点 所以你对该组件的任何操作都会失效

你也可以使用简写 <>jsx</>

StrictMode

使用脚手架创建项目时 默认会在跟标签外面包裹StrictMode

Fragment一样 StrictMode不会创建任何 UI 元素 正如字面意思一样 它主要用于

  • 识别不安全的生命周期

  • 使用过时的 ref 的 API

  • 检查意外的副作用

    • 开发环境下会调用两次 constructor

  • 识别废弃的 findDOMNode 方法

  • 检测过时的 context API

错误边界

错误边界依赖 componentDidCatch 这个生命周期函数 所以目前只有类组件能够实现错误边界

错误边界能够帮助我们在页面出错的情况下 降级 UI 而不至于页面崩溃

下面贴一段官网的 demo

</details>

Render Props

Render Props

render prop 是一个用于告知组件需要渲染什么内容的函数 prop

https://react.docschina.org/docs/render-props.html

高阶组件

高阶组件就是一个函数 它接收一个组件 并返回一个新的组件

主要功能有

  • 可操作所有传入的 props

  • 可操作组件的生命周期

  • 可操作组件的 static 方法

  • 获取 refs

  • 可操作 state

  • 可以渲染劫持

类型检查

如果你的项目还未使用 typescript 又想约束类型的话

你大概会使用到这个库 prop-types

但是prop-types只做 warning 层面的警告 ⚠️ 它不会打断我们的程序

Last updated

Was this helpful?