React学习笔记六

HaoOuBa
2021-06-08 / 0 评论 / 181 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2021年06月09日,已超过537天没有更新,若内容或图片失效,请留言反馈。

React拓展 - setState

setState更新状态的两种写法

1、setState({}, [callback])

export default class Test extends Component {
  state = {count: 0}
  add = () => {
    const { count } = this.state
    this.setState({ count: 8 })
    console.log(this.state.count) // 0 因为setState是异步的,所以会先执行这个

    // 如果想要在setState操作后,拿state里的值进行操作,需要使用第二个回调函数或async await实现
    this.setState({ count: 8 }, () => {
      console.log(this.state.count) // 8
    })
  }
}

2、setState(updater, [callback])

export default class Test extends Component {
  state = {count: 0}
  add = () => {
    // 通过函数式,可以获取到state和props
    this.setState((state, props) => {
      console.log(state, props)
      return { count: state.count + 1 }
    }, () => {
       console.log(this.state.count) // 1
    })
  }
}

React拓展 - lazyLoad

路由懒加载

import {Component, lazy, Suspense} from "react"
// 懒加载路由模块
const Home = lazy(() => import("./Home/index"))
const About = lazy(() => import("./About/index"))
export default class Test extends Component {
  render() {
    return (
      <div>
        {/* Suspense 用于网络不好的时候,显示一个loading加载 */}
        <Suspense fallback={<h1>Loading...</h1>}>
          <Route path="/home" component={Home}>
          <Route path="/about" component={About}>
        </Suspense>
      </div>
    )
  }
}

React拓展 - State Hook

State Hook 为了让使用者在函数式组件里使用state

import React from 'react';
export default function Test2() {
    // React.useState() 用于初始化一个值,返回一个数组
    // 数组第一个值为初始化的值
    // 第二值为一个函数,用于修改第一个值
    const [count, setCount] = React.useState(0);
    const [name, setName] = React.useState('杜恒');

    // 点击事件的回调
    const changeCount = () => setCount(count + 1);
    const changeName = () => setName('帅气的杜恒');

    return (
        <div>
            <h2>当前值为:{count}</h2>
            <button onClick={changeCount}>+ 1</button>
            <hr />
            <h2>当前名为:{name}</h2>
            <button onClick={changeName}>改名</button>
        </div>
    );
}

React拓展 - Effect Hook

Effect Hook 为了让使用者在函数式组件里使用生命周期钩子

import React from 'react';
export default function Test2() {
    const [count, setCount] = React.useState(0);
    // React.useEffect 接收两个参数
    // 第一个参数为函数,这个函数可以用作2个生命周期
    //   componentDidMount 或 componentDidUpdate
    // 第二个参数为数组,这个数组用于监听state里的值
    //   如果为空数组,则第一个参数当componentDidMount使用(只调用一次)
    //   如果第二个参数没写或数组有值,则第一个参数当componentDidUpdate使用
    React.useEffect(() => {
        let timer = setInterval(() => {
            setCount(count => count + 1);
        }, 1000);
        // 当return函数出去时,这个return出去的函数就可以当componentWillUnmount使用
        return () => {
            clearInterval(timer);
        };
    }, []);

    return (
        <div>
            <h2>当前值为:{count}</h2>
        </div>
    );
}

React拓展 - Ref Hook

Ref Hook 和类式组件里面的createRef一样

import React from 'react';
export default function Test2() {
    const inputRef = React.useRef();
    const show = () => console.log(inputRef);
    return (
        <div>
            <input type="text" ref={inputRef} />
            <button onClick={show}>点击提示</button>
        </div>
    );
}

React拓展 - Fragment

用于多个标签时包裹使用

import React, {Fragment} from 'react';
export default function Test2() {
    return (
        <Fragment>
            <input type="text" />
            <input type="text" />
        </Fragment>
    );
}

上面的写法可以写成下面的,直接使用空标签

import React, {Fragment} from 'react';
export default function Test2() {
    return (
        <>
            <input type="text" />
            <input type="text" />
        </>
    );
}

React拓展 - Context

Context 用于祖组件向后台组件通信

import React, { Component } from 'react';

// 1. 创建TestContext容器
const TestContext = React.createContext();

export default class A extends Component {
    state = { name: '杜恒' };
    render() {
        return (
            <div style={{ background: 'orange', padding: 10 }}>
                我是A组件
                {/* 2. 通过 Provider 将所有的state传入到后代组件里 */}
                <TestContext.Provider value={this.state}>
                    <B />
                </TestContext.Provider>
            </div>
        );
    }
}
class B extends Component {
    render() {
        return (
            <div>
                我是B组件
                <C />
            </div>
        );
    }
}

// 第一种方式
class C extends Component {
    /* 3. 申明使用context */
    static contextType = TestContext;
    render() {
        console.log(this.context); // {name: "杜恒"}
        return <div>我是C组件</div>;
    }
}

// 第二种方式
function C() {
  return (
    <div>
      <TestContext.Consumer>
        { value => console.log(value) }
      </TestContext.Consumer>
    </div>
  )
}

React拓展 - 组件优化

组件有以下2个问题

  1. 组件内执行了setState,即使不改变状态数据,也会触发render更新
  2. 父组件render发生更新,会导致子组件的render也会触发
由于render受shouldComponentUpdate的阀门控制,因此需要在shouldComponentUpdate钩子里进行操作
import { Component } from 'react';
export default class A extends Component {
    state = { count: 0 };
    /* 赋值一个空对象,并没有改变state的值,也会触发更新 */
    add = () => this.setState({});
    /* 通过控制shouldComponentUpdate的返回值,控制是否触发render */
    shouldComponentUpdate(nextProps, nextState) {
        console.log(nextProps, nextState);
        return !this.state.count === nextState.count;
    }
    render() {
        console.log('render函数被触发了');
        return <button onClick={this.add}>{this.state.count}</button>;
    }
}

import { PureComponent } from 'react';
export default class A extends PureComponent {
    state = { count: 0 };
    add = () => this.setState({});
    render() {
        console.log('render函数被触发了');
        return <button onClick={this.add}>{this.state.count}</button>;
    }
}

React拓展 - Render Props

import { PureComponent } from 'react';
export default class A extends PureComponent {
    render() {
        return (
            <div>
                <h3>我是A组件</h3>
                <B render={name => <C name={name} />}></B>
            </div>
        );
    }
}
class B extends PureComponent {
    state = { name: '杜恒' };
    render() {
        return (
            <div>
                <h3>我是B组件</h3>
                {/* 类似插槽的功能 */}
                {this.props.render(this.state.name)}
            </div>
        );
    }
}
class C extends PureComponent {
    render() {
        console.log(this.props);
        return <div>我是C组件</div>;
    }
}

错误边界

错误边界用于当子组件出错时,控制错误范围在父组件,不会影响到其他的组件。错误边界只能在生产环境使用,开发环境会一闪而过

import { PureComponent } from 'react';
export default class A extends PureComponent {
    /* 父组件定义一个状态,用于判断是否出错 */
    state = {hasError: ''};
    /* 当后代组件生命周期里有错误时,会触发该函数 */
    static getDerivedStateFromError(error) {
        return { hasError: error };
    }
    /* 这里可以抓捕到错误后,将错误发送给服务器,服务器在通知到钉钉等 */
    componentDidCatch() {
      console.log('组件发生错误!')
    }
    render() {
        return (
            <div>
                <h3>我是A组件</h3>
                {/* 动态渲染组件 */}
                {this.state.hasError ? <h2>子组件出错</h2> : <B />}
            </div>
        );
    }
}
class B extends PureComponent {
    state = { name: '杜恒' };
    render() {
        return (
            <div>
                <h3>我是B组件</h3>
                {this.state.name.map(() => (
                    <span>666</span>
                ))}
            </div>
        );
    }
}
1

评论 (0)

取消