0.React生命周期
1.组件的复用
两种方式:
- render props模式
- 高阶组件(HOC)
render-props模式
组件的作用是为了复用,复用的有数据+视图. 其中一种复用机制就是
render-props:只复用数据,视图在使用的时候传过来. 本质: 是一个类组件,组件内部render方法里面return的内容 是 调用this.props.render()方法返回的内容。 -思路:
- 将要复用的state和操作state的方法封装到一个组件中
- 在使用组件时,添加一个值为函数的prop,通过函数参数来获取
- 使用该函数的返回值作为要渲染的UI内容
使用步骤
- 创建MyMouse 组件,在组件中提供复用的逻辑代码
- 将要复用的状态作为
props.render(state)方法的参数,暴露到组件外部- 使用props.render() 的返回值作为要渲染的内容
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// 引入类组件
import MyMouse from './MyMouse'
// 引入图片
import img from './image/5.jpg'
ReactDOM.render(<div>
<MyMouse
// 只传递数据,图片需要用时再传
render={
(data) => <img src={img} style={{ position: 'absolute', top: data.y, left: data.x }}></img>
// (data) => <div> x为:{data.x},y为:{data.y}</div>
}
/>
</div>, document.getElementById('root'));
//MyMouse.js
import { Component } from 'react'
export default class MyMouse extends Component {
state = {
x: "",
y: ""
}
// 鼠标移动触发
handelMouse = (e) => {
// console.log(e);
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 创建时,挂载完DOM时触发
componentDidMount() {
window.addEventListener('mousemove', this.handelMouse)
}
// 释放
componentWillUnmount() {
window.removeEventListener('mousemove', this.handelMouse)
}
render() {
return this.props.render(this.state)
}
}
鼠标跟随效果
render-props模式的children写法
- 注意:并不是该模式叫 render props就必须使用名为render的prop,实际上可以使用任意名称的prop
- 把prop是一个函数并且告诉组件要渲染什么内容的技术叫做: render props模式
- 推荐:使用childre代替render属性
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
// 引入类组件
import MyMouse from './MyMouse'
ReactDOM.render(<div>
<MyMouse>{(data) => <div> x为:{data.x},y为:{data.y}</div>}</MyMouse>
</div>, document.getElementById('root'));
//MyMouse.js
import { Component } from 'react'
// 引入类型模块
import propTypes from 'prop-types'
export default class MyMouse extends Component {
state = {
x: "",
y: ""
}
// 鼠标移动触发
handelMouse = (e) => {
// console.log(e);
this.setState({
x: e.clientX,
y: e.clientY
})
}
// 创建时,挂载完DOM时触发
componentDidMount() {
window.addEventListener('mousemove', this.handelMouse)
}
// 释放
componentWillUnmount() {
window.removeEventListener('mousemove', this.handelMouse)
}
render() {
return this.props.children(this.state)
}
}
// 校验
MyMouse.propTypes = {
children: propTypes.func.isRequired
}
高阶组件(HOC)
函数接收一个组件,返回增强后的组件 使用步骤
- 创建一个函数,名称约定以with开头
- 指定函数参数,参数应该以大写字母开头
- 在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
- 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
- 调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import img from './image/5.jpg'
// 1.函数接收一个组件,返回增强后的组件
// 名称约定以with开头
// 指定函数参数,参数应该以大写字母开头
function withMouse(WrapperedComponent) {
// 2.在函数内部创建一个类组件,提供复用的状态逻辑代码,并返回
class Mouse extends Component {
state = {
x: "",
y: ""
}
handelMouse = (e) => {
console.log(e);
this.setState({
x: e.clientX,
y: e.clientY
});
}
// 3.在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件
render() {
return <WrapperedComponent {...this.state} />
}
// 创建时,挂载完DOM时触发
componentDidMount() {
window.addEventListener('mousemove', this.handelMouse)
}
// 释放
componentWillUnmount() {
window.removeEventListener('mousemove', this.handelMouse)
}
}
return Mouse;
}
const Position = (props) => <h3>x为:{props.x},y为:{props.y}</h3>
const Dog = (props) => <img src={img} style={{ position: 'absolute', top: props.y, left: props.x }}></img>
// 4.调用该高阶组件,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面
const PositionWrapped = withMouse(Position)
const TomcatWrapped = withMouse(Dog)
ReactDOM.render(<div>
<PositionWrapped />
<TomcatWrapped />
</div>, document.getElementById('root'));
修改高阶组件别名displayName
const PositionWrapped = withMouse(Position)
PositionWrapped.displayName = 'PositionWrapped'
效果
传递props
2.React原理
setState()
- setState是异步
- 在render之后执行
- 多次调用setState,只会触发一次render(第五条是解决办法)
- setState第二个有回调函数,可以拿到state改变之后的值
- setState第一个参数可以使用函数,函数的形参是上一次setState改变之后的state和props
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
state = {
count: 0
}
handelClick = () => {
this.setState({
count: this.state.count + 1
}, function () {
// 执行顺序三
console.log('setState内:' + this.state.count);
})
// 执行顺序一
console.log('setState外:' + this.state.count);
}
render() {
// 执行顺序二
console.log('renser内:' + this.state.count);
return (
<div>
<h3>点击次数为:{this.state.count}</h3>
<button onClick={this.handelClick}>+</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
使用函数与对象的方式
推荐:使用
setState((preState, preProps) => {})语法
//index.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
state = {
count: 0
}
handelClick = () => {
// setState第一个参数可以使用函数,函数的形参是上一次setState改变之后的state和props
//以下代码可以叠加呈现
this.setState((preState, preProps) => {
console.log(preState, preProps);
return { count: preState.count + 1 }
})
this.setState((preState, preProps) => {
console.log(preState, preProps);
return { count: preState.count + 1 }
})
this.setState((preState, preProps) => {
console.log(preState, preProps);
return { count: preState.count + 1 }
})
// 以下方式只会触发一次
// this.setState({
// count: this.state.count + 1
// })
// console.log(this.state.count);
// this.setState({
// count: this.state.count + 1
// })
// console.log(this.state.count);
// this.setState({
// count: this.state.count + 1
// })
// console.log(this.state.count);
}
render() {
return (
<div>
<h3>点击次数为:{this.state.count}</h3>
<button onClick={this.handelClick}>+</button>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));