扬帆起航
注:本章节的 demo 都以
类组件 + TS为例 等下一章 hook 章节后都为函数式组件UI 库 统一使用
antdhttps://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 你可以戳 👉这篇文章
解决的方法有两种
手动绑定 this 在父组件的构造函数处 手动绑定为方法 绑定 this
使用箭头函数
生命周期函数
主要参考官方的生命周期图谱
具体有关生命周期的内容 我会在下几章中更新
这里 我只提最常用的几个生命周期函数以及它们的用途
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
高阶组件
高阶组件就是一个函数 它接收一个组件 并返回一个新的组件
主要功能有
可操作所有传入的 props
可操作组件的生命周期
可操作组件的 static 方法
获取 refs
可操作 state
可以渲染劫持
类型检查
如果你的项目还未使用 typescript 又想约束类型的话
你大概会使用到这个库 prop-types
但是prop-types只做 warning 层面的警告 ⚠️ 它不会打断我们的程序
Last updated
Was this helpful?