快速上手React(下)

503 阅读4分钟

0.React生命周期

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()

  1. setState是异步
  2. 在render之后执行
  3. 多次调用setState,只会触发一次render(第五条是解决办法)
  4. setState第二个有回调函数,可以拿到state改变之后的值
  5. 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'));

在这里插入图片描述