react相关基础
# React
# 生命周期
# 图示
React 16.3 版本之前 生命周期
React 新版 生命周期
# 组件通信
- props,父子通信
- 回调函数,子父通信
- 变量提升,兄弟组建通信
- Context,跨组建通信
- node的events模块的单例通信
- redux共享数据通信
# 样式配合
# 样式化加载
有多种方法可用于对 React 组件进行样式设置,每种方法各有利弊。要提到的主要是:
- 内联样式:适用于原型设计,但有局限性(例如,无伪类样式)
- 基于类的CSS样式:比内联样式更高效,并且对 React 刚接触的开发人员来说是熟悉的
- JS样式中的CSS:有许多库允许将样式在组件内声明为 JavaScript,从而将样式更像代码。
参考文章:react-components-styling-options (opens new window)
- inline CSS
- normal CSS
- CSS in JS libraries
- CSS Modules
- Sass & SCSS
- Less
- Stylable
# 前端富文本实现
const rawHtml = '<div><p>Title</p></div>'
const rawHtmlData = {
__html: rawHtml // 这里有个下划线
}
return <div dangerouslySetInnerHTML={rawHtmlData}></div>
2
3
4
5
# jsx
每个 JSX 元素只是调用
React.createElement(component, props, ...children)
的语法糖。因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成
本质:JSX => React.createElement() => 虚拟DOM (JS对象) => 真实DOM
# 为什么使用jsx的组件中没有看到使用react却需要引入react?
本质上来说JSX是React.createElement(component, props, ...children)
方法的语法糖。在React 17之前,如果使用了JSX,其实就是在使用React, babel
会把组件转换为 CreateElement
形式。在React 17之后,就不再需要引入,因为 babel
已经可以帮我们自动引入react。
# 如何 React.createElement ?
const element = (
<h1 className="greeting">
Hello, world!
</h1>
)
2
3
4
5
上述代码如何使用 React.createElement
来实现:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
2
3
4
5
# Hooks
# 10个API
- Basic Hooks
useState
(opens new window)【维护状态】useEffect
(opens new window)【完成副作用操作】useContext
(opens new window)【使用共享状态】
- Additional Hooks
useReducer
(opens new window)【类似redux】useCallback
(opens new window)【缓存函数】useMemo
(opens new window)【缓存值】useRef
(opens new window)【访问DOM】useImperativeHandle
(opens new window)【使用子组件暴露的值/方法】useLayoutEffect
(opens new window)【完成副作用操作,会阻塞浏览器绘制】useDebugValue
(opens new window)【开发者工具中显示自定义 hook 的标签】
# useEffet
我们可以理解成它替换了componentDidMount
, componentDidUpdate
, componentWillUnmount
这三个生命周期,但是它的功能还更强大。
包含3个生命周期的代码结构
// => componentDidMount/componentDidUpdate
useEffect(() => {
// 这里的代码块 等价于 componentDidMount
// do something...
// return的写法 等价于 componentWillUnmount
return () => {
// do something...
};
},
// 依赖列表,当依赖的值有变更时候,执行副作用函数,等价于 componentDidUpdate
[ xxx,obj.xxx ]
);
2
3
4
5
6
7
8
9
10
11
12
13
注意:依赖列表是灵活的,有三种写法
- 当数组为空
[ ]
,表示不会应为页面的状态改变而执行回调方法【即仅在初始化时执行,componentDidMount
】, - 当这个参数不传递,表示页面的任何状态一旦变更都会执行回调方法
- 当数组非空,数组里的值一旦有变化,就会执行回调方法
# 模拟React的生命周期
- constructor:函数组件不需要构造函数。你可以通过调用 useState 来初始化 state。
- componentDidMount:通过 useEffect 传入第二个参数为[]实现。
- componentDidUpdate:通过 useEffect 传入第二个参数为空或者为值变动的数组。
- componentWillUnmount:主要用来清除副作用。通过 useEffect 函数 return 一个函数来模拟。
- shouldComponentUpdate:你可以用 React.memo 包裹一个组件来对它的 props 进行浅比较。来模拟是否更新组件。
- componentDidCatch and getDerivedStateFromError:目前还没有这些方法的 Hook 等价写法,但很快会加上。
# 性能优化
# 总括
性能优化,永远是面试的重点,性能优化对于 React 更加重要
- 在页面中使用了
setTimout()
、addEventListener()
等,要及时在componentWillUnmount()
中销毁 - 使用异步组件
- 使用
React-loadable
动态加载组件 shouldComponentUpdate
(简称SCU )、React.PureComponent
、React.memo
- 不可变值 ImmutableJS
shouldComponentUpdate (nextProps, nextState) {
return true // 可以渲染,执行 render(),默认返回 true
return false // 不能渲染,不执行 render()
}
2
3
4
# 详细分类
# 什么情况下需要使用 shouldComponentUpdate
在React中,默认情况下,如果父组件数据发生了更新,那么所有子组件都会无条件更新 !!!!!! 通过
shouldComponentUpdate()
retrun fasle 来判断阻止 Header 组件做无意义的更新shouldComponentUpdate()
并不是每次都需要使用,而是需要的时候才会优化
class App extends React.Component {
constructor () {
this.state = { list: [] }
}
render () {
return (
<div>
{/* 当list数据发生变化时,Header组件也会更新,调用 render() */}
<Header />
<List data={this.state.list}
</div>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
在shouldComponentUpdate()
判断中,有一个有意思的问题,解释为什么 React setState()
要用不可变值
// 父组件中
changeList () {
this.state.list.push({id: 2})
this.setState({
list: this.state.list
})
}
// 子组件中
import _ from 'lodash'
shouldComponentUpdate(nextProps, nextState) {
// 数组深度比较(一次性递归到底,耗费性能,工作中慎用)
if (_.isEqual(nextProps.list, this.props.list)) {
return false // 相等,不渲染
}
return true // 不相等,渲染
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
子组件将始终不会渲染,因为在
shouldComponentUpdate()
中,this.state.list.push()
已经修改了this.props.list
,而this.setState()
修改了nextProps.list
所以两个值深度比较,将始终相同。
# PureComponent 和 memo
- class类组件中用
PureComponent
,无状态组件(无状态)中用memo
- PureComponent, SCU中实现了浅比较
- 浅比较已使用大部分情况(尽量不要做深度比较)
PureComponent 与普通 Component 不同的地方在于,PureComponent自带了一个
shouldComponentUpdate()
,并且进行了浅比较
// memo用法
function MyComponent (props) {
/* 使用 props 渲染 */
}
// areEqual 也可不传
function areEqual(prevProps, nextProps) {
if (prevProps.seconds===nextProps.seconds) {
return true
} else {
return false
}
}
export default React.memo(MyComponent, areEqual)
2
3
4
5
6
7
8
9
10
11
12
13
# immutable.js
- 彻底拥抱“不可变值”
- 基础共享数据(不是深拷贝),速度快
- 有一定学习和迁移成本
# 参考链接
https://zh-hans.reactjs.org/docs/getting-started.html