# react-extension-study
**Repository Path**: lzxjack/react-extension-study
## Basic Information
- **Project Name**: react-extension-study
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-04-21
- **Last Updated**: 2021-04-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 1. setState
使用`setState`更新状态有 2 种写法。
`对象式`是`函数式`的简写方式(语法糖)。
**使用原则(非必须):**
- 新状态**不依赖于**原状态 ===> 使用`对象式`
- 新状态**依赖于**原状态 ===> 使用`函数式`
- 如果需要在`setState()`执行后获取最新的状态数据,要在`callback`函数中读取
## 1. 对象式
```javascript
setState(stateChange, [callback]);
```
- `stateChange`为状态改变对象(该对象可以体现出状态的更改)
- `callback`是可选的回调函数, 它在状态更新完毕、界面也更新后(`render`调用后)才被调用
- 状态的更新是`异步`的,如果想要查看`更新后的状态`,需要写在`callback`中
```javascript
const { count } = this.state;
this.setState({ count: count + 1 }, () => {
console.log(this.state.count);
});
```
## 2. 函数式
```javascript
setState(updater, [callback]);
```
- `updater`为返回`stateChange`对象的函数,可以接收到`state`和`props`
- `callback`是可选的回调函数, 它在状态更新完毕、界面也更新后(`render`调用后)才被调用
```
this.setState((state, props) => ({ count: state.count + 1 }));
```
# 2. 路由组件的lazyLoad
通过 React 的`lazy`函数配合`import()`函数动态加载路由组件,使路由组件代码分开打包。
```javascript
import Loading from './Loading';
const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
```
通过``标签指定在加载得到路由打包文件前显示一个自定义`loading界面`。
```javascript
}>
{/* 注册路由 */}
```
# 3. Hooks
`Hook`是 React 16.8.0 版本增加的新特性,可以在`函数组件`中使用`state`以及其他的 React 特性。下面介绍三个常用的`Hook`:
- State Hook:`React.useState()`
- Effect Hook:`React.useEffect()`
- Ref Hook:`React.useRef()`
## 1. State Hook
State Hook 让函数组件也可以有`state`状态,并进行状态数据的读写操作。
```javascript
const [xxx, setXxx] = React.useState(initValue); // 解构赋值
```
- `useState()`
参数:第一次初始化指定的值在内部作缓存
返回值:包含 2 个元素的数组,第 1 个为内部当前状态值,第 2 个为更新状态值的函数
- `setXxx()`2 种写法
`setXxx(newValue)`:参数为非函数值,直接指定新的状态值,内部用其覆盖原来的状态值
`setXxx(value => newValue)`:参数为函数,接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值
```javascript
function Demo() {
const [count, setCount] = React.useState(0);
//加的回调
function add() {
// 第一种写法
// setCount(count + 1);
// 第二种写法
setCount(count => count + 1);
}
return (
当前求和为:{count}
);
}
```
## 2. Effect Hook
Effect Hook 可以在函数组件中执行`副作用操作`(用于模拟类组件中的生命周期钩子)。
React 中的`副作用操作`:
- 发`ajax`请求数据获取
- 设置订阅 / 启动定时器
- 手动更改真实 DOM
```javascript
useEffect(() => {
// 在此可以执行任何带副作用操作
// 相当于componentDidMount()
return () => {
// 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
// 相当于componentWillUnmount()
};
}, [stateValue]); // 监听stateValue
// 如果省略数组,则检测所有的状态,状态有更新就又调用一次回调函数
// 如果指定的是[], 回调函数只会在第一次render()后执行
```
可以把`useEffect()`看做如下三个函数的组合:
- `componentDidMount()`
- `componentDidUpdate()`
- `componentWillUnmount() `
```javascript
function Demo() {
const [count, setCount] = React.useState(0);
React.useEffect(() => {
let timer = setInterval(() => {
setCount(count => count + 1);
}, 500);
console.log('@@@@');
return () => {
clearInterval(timer);
};
}, [count]);
// 检测count的变化,每次变化,都会输出'@@@@'
//加的回调
function add() {
// 第一种写法
// setCount(count + 1);
// 第二种写法
setCount(count => count + 1);
}
// 卸载组件的回调;
function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('root'));
}
return (
当前求和为:{count}
);
}
```
## 3. Ref Hook
Ref Hook 可以在函数组件中存储/查找组件内的标签或任意其它数据。
保存标签对象,功能与`React.createRef()`一样
```javascript
const refContainer = useRef();
```
```javascript
function Demo() {
const myRef = React.useRef();
//提示输入的回调
function show() {
alert(myRef.current.value);
}
return (
);
}
```
# 4. Fragment
使用``后,可以不用必须有一个真实的 DOM 根标签了。
```javascript
import React, { Component, Fragment } from 'react';
export default class Demo extends Component {
render() {
return (
);
}
}
```
使用空标签`<>>`包裹也可以,他们的区别如下:
- ``:可以接收`key`属性,不能接收其他属性
- `<>>`:不能接受属性
# 5. Context
一种组件间通信方式,常用于`祖组件`与`后代组件`间通信。
在组件外部创建`Context`容器对象:
```javascript
const XxxContext = React.createContext();
```
渲染子组时,外面包裹`xxxContext.Provider`,通过`value`属性给后代组件传递数据:
```javascript
子组件
```
后代组件读取数据:
方式(1),仅适用于`类组件`:
```javascript
static contextType = xxxContext // 声明接收context
console.log(this.context); // 读取context中的value数据
```
方式(2),`函数组件`与`类组件`都可以:
```javascript
{value => `${value.username},年龄是${value.age}`}
```
# 6. 组件优化
React 中`Component`组件的2个问题:
1. 只要执行`setState()`,即使**不改变状态数据**,组件也会重新`render()`
2. 只要当前组件重新`render`,就会自动重新`render`子组件,即使子组件没有发生任何变化,这导致页面更新的效率低下
效率高的做法:
- 只有当组件的`state`或`props`数据发生改变时才重新`render()`。
问题的原因:
- `Component`中的`shouldComponentUpdate()`总是返回`true`
解决办法:
- 重写`shouldComponentUpdate()`方法
比较新旧`state`或`props`数据,如果有变化才返回`true`,否则返回`false`
- 使用`PureComponent`组件代替`Component`组件
`PureComponent`重写了`shouldComponentUpdate()`,只有`state`或`props`数据有变化才返回`true`
只是进行`state`和`props`数据的`浅比较`,如果只是数据对象内部数据变了,返回`false`
所以不要直接修改`state`数据,而是要**产生新数据**
# 7. render props
向组件内部动态传入带内容的结构(标签)。
## 1. children props
```javascript
xxxx
```
`B`组件通过`this.props.children`获取便签中的数据。
但是`B`组件获得不到`A`组件内的数据。
## 2. render props
```javascript
export default class Parent extends Component {
render() {
return (
);
}
}
class A extends Component {
state = { name: 'tom' };
render() {
console.log(this.props);
const { name } = this.state;
return (
我是A组件
{this.props.render(name)}
);
}
}
class B extends Component {
render() {
console.log('B--render');
return (
我是B组件,{this.props.name}
);
}
}
```
相当于`A`组件内部写了个插槽,可以在`Parent`组件中任意更改向插槽中插入的组件,并传递`A`组件的数据。
# 8. 错误边界
用来捕获后代组件错误,渲染出备用页面。
只能捕获后代组件`生命周期`产生的错误,不能捕获自己组件产生的错误和其他组件在合成事件、定时器中产生的错误。
`getDerivedStateFromError` + `componentDidCatch`
```javascript
export default class Parent extends Component {
state = {
hasError: '', // 用于标识子组件是否产生错误
};
//当Parent的子组件出现报错时候,会触发getDerivedStateFromError调用,并携带错误信息
static getDerivedStateFromError(error) {
console.log('@@@', error);
// 返回状态对象
return { hasError: error };
}
componentDidCatch(error, info) {
// 统计页面的错误。发送请求发送到后台去
console.log(error, info);
}
render() {
return (
我是Parent组件
{this.state.hasError ? 当前网络不稳定,稍后再试
: }
);
}
}
```
# 9. 组件间通信方式总结
通信方式:
1. `props`
父子间通过`props`
`children props`
`render props`
2. 消息订阅-发布
`pubs-sub`等
3. 集中式管理
`redux`等
4. `conText`
生产者-消费者模式
组件之间的关系:
1. 父子组件 —— `props`
2. 兄弟组件(非嵌套组件) —— 消息订阅-发布、集中式管理
3. 祖孙组件(跨级组件) —— 消息订阅-发布、集中式管理、`conText`
***
欢迎在我的博客上访问:
https://lzxjack.top/article/React_extension.html