React拓展
setState
对象式
setState(stateChange, [callback]) ------对象式的 setState , setState 引起的后续动作是异步的。
state = { count: 0 }
add = () => {
this.setState({count: count + 1})
console.log(this.state.count) // 这里输出0,因为setState异步操作还没执行
}
stateChange为状态改变对象(该对象可以体现出状态的更改)。callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用。state = { count: 0 } add = () => { this.setState({count: count + 1}, () => { console.log(this.state.count) // 1 }) }
函数式
setState(updater, [callback]) ------函数式的 setState 。
updater为返回stateChange对象的函数。updater可以接收到state和props。callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
state = { count: 0 }
add = () => {
this.setState((state, props) => {
return {count: state.count + 1} // 可以通过形参获取state内的值
})
}
总结
- 对象式的
setState是函数式的setState的简写方式(语法糖)。 - 使用原则:
- 如果新状态不依赖于原状态 ===> 使用对象方式。
- 如果新状态依赖于原状态 ===> 使用函数方式。
- 如果需要在
setState()执行后获取最新的状态数据,要在第二个callback函数中读取。
lazyLoad
路由组件无论看与不看都已经都引进来了,可以使用路由懒加载优化。
使用方法:
-
引入
lazy函数import {lazy} from 'react' -
路由调用
lazy函数通过
React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包。const Home = lazy(() => import('./Home')) -
引入
Suspense组件通过
<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面。import {lazy, Suspense} from 'react' import Loading from './Loading' // loading组件不能用懒加载了 <Suspense fallback={<Loading />}> <Route path="./home" component={Home}></Route> </Suspense>
hooks
函数式组件在 16.8 版本前没有自己的 this 指向,因此使用不了 state 和 action ,因此没有类式组件好用。
是什么
Hook是React 16.8.0版本增加的新特性/新语法。- 可以让你在函数组件中使用
state以及其他的React特性。
State Hook
State Hook 让函数组件也可以有 state 状态,并进行状态数据的读写操作。
语法: const [xxx, setXxx] = React.useState(initValue)
useState() 说明:
- 参数:第一次初始化指定的值在内部作缓存。
- 返回值:包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数。
import React from 'react'
function Demo() {
const [count, setCount] = React.useState(0) // 定义state的值,每一次调用都会执行,如果没有count,赋初始值0,如果有,则缓存这个值,覆盖0
add = () => {
setCount(count + 1)
}
return (
<div>{count}</div>
<button onClick={add}></button>
)
}
setXxx() 2种写法:
setXxx(newValue): 参数为非函数值,直接指定新的状态值,内部用其覆盖原来的状态值。setXxx(value => newValue):参数为函数,接收原本的状态值, 返回新的状态值,内部用其覆盖原来的状态值。add = () => { setCount(count => count + 1) }
Effect Hook
Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)。
语法和说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
[stateValue] 是一个可选参数,如果都不写,state的值发生变化也会触发。如果设为空数组,谁也不监测,挂载时触发一次。
import React from 'react'
function Demo() {
React.useEffect(() => {
console.log('@')
}, []) // 类似componentDidMount钩子函数,挂载时触发一次
return (
<div></div>
)
}
总结:
可以把 useEffect Hook 看做如下三个函数的组合:
componentDidMount():第二个参数为[]componentDidUpdate():第二个参数不填componentWillUnmount():在第一个参数中返回一个函数。
Ref Hook
Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据。
语法:
const refContainer = useRef()
作用:保存标签对象,功能与React.createRef() 一样。
Fragment
作用:可以不用必须有一个真实的DOM根标签了
使用
import {Fragment} from 'react'
<Fragment><Fragment>
<></>
Context
一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信。
使用
- 创建Context容器对象:
const XxxContext = React.createContext() - 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
<xxxContext.Provider value={数据}> 子组件 </xxxContext.Provider>
- 后代组件读取数据:
//第一种方式:仅适用于类组件 static contextType = xxxContext // 声明接收context this.context // 读取context中的value数据 第二种方式: 函数组件与类组件都可以 <xxxContext.Consumer> { value => ( // value就是context中的value数据 要显示的内容 ) } </xxxContext.Consumer>
注意:
在应用开发中一般不用
context, 一般都用它的封装react插件。
Component的2个问题
- 只要执行
setState(),即使不改变状态数据,组件也会重新render()==> 效率低。- 只当前组件重新
render(),就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==> 效率低
当组件的state或props数据发生改变时才重新render()。
解决办法:
-
重写
shouldComponentUpdate()方法比较新旧
state或props数据, 如果有变化才返回true, 如果没有返回false。 -
使用
PureComponentPureComponent重写了shouldComponentUpdate(),只有state或props数据有变化才返回true。import {PureComponent} from 'react' class Child extends PureComponent {}
注意:
- 只是进行
state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false。- 不要直接修改
state数据, 而是要产生新数据,因为对象的地址没有发生改变。- 项目中一般使用
PureComponent来优化。
render props
如何向组件内部动态传入带内容的结构(标签)?
Vue中:使用slot技术, 也就是通过组件标签体传入结构
<A><B/></A>
React中:
-
使用
children props:通过组件标签体传入结构。<A> <B>xxxx</B> </A> {this.props.children}问题: 如果B组件需要A组件内的数据, ==> 做不到
-
使用
render props:通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性<A render={(data) => <C data={data}></C>}></A>A组件:
{this.props.render(内部state数据)}C组件: 读取A组件传入的数据显示
{this.props.data}
组件通信
父子组件
props:children props;render props
兄弟组件
消息订阅-发布pubs-sub、集中式管理redux
祖孙组件
消息订阅-发布、集中式管理、context