生命周期
一个应用或页面从创建到消亡过程中某一时刻自动调用的回调函数称为生命周期钩子函数
挂载
- constructor :来初始化函数内部 state,为 事件处理函数 绑定实例
- render:渲染 DOM
- componentDidMount:组件挂载、DOM 渲染完后,可以发送网络请求并进行 DOM 操作
更新
- shouldComponentUpdate:组件更新之前调用,可以控制组件是否进行更新, 返回true时组件更新, 返回false则不更新。它包含两个参数,第一个是即将更新的 props 值,第二个是即将更新后的 state 值,可以根据更新前后的 props 或 state 来比较加一些限制条件,决定是否更新,进行性能优化
- render
- componentDidUpdate:会在更新后会被立即调用,首次渲染不会执行。包含三个参数,第一个是上一次 props 值。 第二个是上一次 state 值。如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),第三个是 snapshot 参数传递
卸载
- componentWillUnmount:组件即将被卸载或销毁时进行调用。可以进行取消网络请求、移除监听事件、清理 DOM 元素、清理定时器等操作
从以上生命周期的对比,我们不难看出,React 从 v16.3 开始废弃 componentWillMount、componentWillReceiveProps、componentWillUpdate 三个钩子函数。
目前 React 为这几个生命周期钩子提供了别名,分别是:
- UNSAFE_componentWillMount
- UNSAFE_componentWillReceiveProps
- UNSAFE_componentWillUpdate
为什么函数式组件没有生命周期!!!!!!!!
函数式组件没有state也没有生命周期。因为他没有继承React.Component ,所以也不需要render()。如果需要使用到生命周期,那么就可以模拟一个什么周期。
【注】
React.PureComponent 与 React.Component:
- Component 没有直接实现 shouldComponentUpdate 这个方法,需要手动实现,而 PureComponent 通过浅层的 porps 和 state 的对比,内部实现了这个生命周期函数。
- 如果你的组件 render 函数渲染时具有相同的 props 和 state,那么可以使用 PureComponent 来提高性能。
- 但 PureComponent 可能会因深层的数据不一致而产生错误的否定判断,从而shouldComponentUpdate 结果返回 false,界面得不到更新。而且PureComponent不仅会影响本身还会影响子组件,所以最好用在数据展示中。
props的传参校验
React 中的 props 传值校验,需要依赖插件,所以需要 npm i prop-types,在引入校验函数 PropTypes
import React from "react";
import PropTypes from 'prop-types'
export default class App extends React.Component{
constructor(props) {
super(props)
this.state={}
}
// React中的props传值校验,需要依赖插件
// 所以需要 npm i prop-types,在引入校验函数 PropTypes
render() {
return (
<div>
<h1>React中props传值校验</h1>
<h2>{this.props.number}</h2>
<h2>{this.props.array}</h2>
<h2>{this.props.string}</h2>
<h2>{ this.props.bool.toString() }</h2>
</div>
)
}
}
//传参校验
App.propTypes = {
number: PropTypes.number,
array: PropTypes.array,
string: PropTypes.string,
bool:PropTypes.bool
}
//默认配置
App.defaultProps = {
number:10000
}
组件渲染传递 RenderProps 的高级复用
RenderProps 概念:将组件的 props 渲染出来。实际上是让组件的 props 接收函数,由函数来渲染内容。将通用的逻辑抽象在该组件的内部,然后依据业务逻辑来调用函数(props内渲染内容的函数),从而达到重用逻辑的目的。
子组件
import React from "react";
// 组件渲染传递renderprops的高级复用
export default class App extends React.Component{
constructor(props) {
super(props)
this.state = {
x: 0,
y:0
}
}
moveFn = (e) => {
this.setState({
x: e.clientX,
y:e.clientY
})
}
//渲染完成生命周期钩子函数
componentDidMount() {
window.addEventListener('mousemove',this.moveFn)
}
render() {
return this.props.fn(this.state)
}
}
父组件
root.render(
<App3
fn = {(a)=> <div><img
src='https://ftp.bmp.ovh/imgs/2021/06/0b6cb6a38f3fdde5.png'
style={{
position:'absolute',
top:a.y-100,
left:a.x-100
}} />
</div>}
/>
);
Redux状态管理器
原理:把数据都放在 store 公共存储空间,一个组件改变了 store 里的数据内容,其他组件就能感知到 store 的变化,再来取数据,从而间接的实现了这些数据传递的功能。
工作流程:React Component 需要获取一些数据, 然后它就告知 Store 需要获取数据,这就是就是Action Creactor , Store 接收到之后去 Reducer 查一下, Reducer 会告诉 Store 应该给这个组件什么数据
Redux的核心
- store:store是redux的核心,整个redux的仓库。
- createStore:可以帮助创建 store,里面有三个参数(reducer,中间件,初始值)
- reducer:是一个纯函数,不需要直接修改 state,派发action
之后,可以通过
store
subscrible.
监听
store的变化。
相当于数据加工用于数据管理的逻辑,里面有两个参数(state,action)。 - action:本质是一个对象,用来告诉 redux 要执行什么任务。
- state:存储 redux 的数据。
- store.dispatch:更改 store 里面数据,是通过 dispatch 来派发 action,通常 action 中都会有type 属性,也可以携带其他的数据。
- store.getState:获取 store 里边所有的数据内容。
- store.subscrible:订阅 store 的改变,只要 store 发生改变, store.subscrible 这个函数接收的这个回调函数就会被执行,进行视图更新。
index.js文件
import { createStore } from 'redux' // 引入createStore方法
import reducer from './reducer'
const store = createStore(reducer)// 创建数据存储仓库
export default store //暴露出去
reducer.js文件
// 全局数据商店管理的 操作函数 以及默认数据
const defaultState = {
}
export default (state = defaultState, action) => {
return state
}
component组件中使用
import React from "react";
import store from "./store/index";
import { Input, Button, List } from "antd";
class TodoList extends React.Component{
constructor(props) {
super(props)
//将redux中的默认defaultState传给当前state
this.state = {
inputValue: '',
data:[]
}
}
//监测input中变化,进行双向数据绑定
changeInputValue = (e) => {
const action = { type: 'changeInput', value: e.target.value }
store.dispatch(action)
}
//在生命周期函数中监测state的变化
componentDidMount() {
var NewInputValue = store.getState().inputValue
var NewData = store.getState().data
this.setState({
inputValue: NewInputValue,
data:NewData
})
store.subscribe(this.storeChange)
}
//当state中的数据变化的时候调用该函数重新渲染,更新redux中的数据
storeChange = () => {
var NewInputValue = store.getState().inputValue
var NewData = store.getState().data
this.setState({
inputValue: NewInputValue,
data:NewData
})
}
//添加
add = () => {
const action = { type: 'add' }
store.dispatch(action)
}
//删除
deleteItem = (index) => {
const action = { type: 'delete', index: index }
store.dispatch(action)
}
render() {
return (
<div style={{ margin: '20px' }}>
<div>
<Input
placeholder="请输入"
style={{ width: '250px', marginRight: '10px' }}
value={this.state.inputValue}
onChange={this.changeInputValue}
/>
<Button type="primary" onClick={this.add}>增加</Button>
</div>
<div
style={{ margin: '10px',width:'500px'}}>
<List
bordered
dataSource={this.state.data}
renderItem={(item,index) => (<List.Item>{item} <Button
type="primary" danger size="small"
style={{float:'right'}}
onClick={this.deleteItem.bind(this,index)}>删除</Button>
</List.Item>)}
/>
</div>
</div>
)
}
}
export default TodoList