• React入门第四天


    ## react-router

    react-router包含3个库, react-router、 react-router-dom和react-router-native。 react-router提供最
    基本的路路由功能,实际使⽤用的时候我们不不会直接安装react-router,⽽而是根据应⽤用运⾏行行的环境选择安装
    react-router-dom(在浏览器器中使⽤用)或react-router-native(在rn中使⽤用)。 react-router-dom和
    react-router-native都依赖react-router,所以在安装时, react-router也会⾃自动安装,创建web应⽤用,
    使⽤用:

    ### 安装

    ```javascript
    npm install --save react-router-dom
    ```

    ### 基本使用

    react-router中奉⾏行行⼀一切皆组件的思想,路路由器器-Router、链接-Link、路路由-Route、独占-Switch、重定向-Redirect都以组件形式存在

    创建RouterPage.js

    ```javascript
    import React,{Component} from 'react';
    import {BrowserRouter as Router,Route,Link} from 'react-router-dom';

    class HomePage extends Component{
    render(){
    return (
    <div>
    <h3>HomePage</h3>
    </div>
    );
    }
    }
    class UserPage extends Component{
    render(){
    return (
    <div>
    <h3>UserPage</h3>
    </div>
    );
    }
    }

    export default class RouterPage extends Component{
    render(){
    return (
    <div>
    <h3>RouterPage</h3>
    <Router>
    <Link to="/">首页</Link>
    <Link to="/user"> 个人中心</Link>
    <Route
    exact
    path="/" component={HomePage}></Route>
    <Route path="/user" component={UserPage}/>

    </Router>
    </div>
    );
    }
    }

    ```

    ### Route渲染内容的三种方式

    Route渲染优先级: children>component>render。
    这三种⽅方式互斥,你只能⽤用⼀一种

    ### children: func

    有时候,不不管location是否匹配,你都需要渲染⼀一些内容,这时候你可以⽤用children。
    除了了不不管location是否匹配都会被渲染之外,其它⼯工作⽅方法与render完全⼀一样。

    ### render: func

    但是当你⽤用render的时候,你调⽤用的只是个函数。
    只在当location匹配的时候渲染

    ### component: component

    只在当location匹配的时候渲染。

    ### 404⻚面

    设定⼀一个没有path的路路由在路路由列列表最后⾯面,表示⼀一定匹配

    ```javascript
    {
    /* 添加Switch表示仅匹配⼀一个*/}
    <Switch>
    {/* 根路路由要添加exact,实现精确匹配 */}
    <Route
    exact
    path="/"
    component={HomePage}
    />
    <Route path="/user" component={UserPage} />
    <Route component={EmptyPage} />
    </Switch>
    ```

    404

    ```javascript
    class EmptyPage extends Component {
    render() {
    return (
    <div>
    <h3>EmptyPage-404</h3>
    </div>
    );
    }
    }
    ```

    ## PureComponent

    ### 实现性能优化

    定制了了shouldComponentUpdate后的Component

    ```javascript
    import React, { Component, PureComponent } from "react";
    export default class PureComponentPage extends PureComponent {
    constructor(props) {
    super(props);
    this.state = {
    counter: 0,
    // obj: {
    // num: 2,
    // },
    };
    }
    setCounter = () => {
    this.setState({
    counter: 100,
    // obj: {
    // num: 200,
    // },
    });
    };
    render() {
    const { counter, obj } = this.state;
    console.log("render");
    return (
    <div>
    <h1>PuerComponentPage</h1>
    <div onClick={this.setCounter}>counter: {counter}</div>
    </div>
    );
    }
    }
    ```

    ### 浅⽐较

    缺点是必须要⽤用class形式,⽽而且要注意是浅比较

    ![1614324445396](C:UsersanatkhAppDataRoamingTypora ypora-user-images1614324445396.png)

    ### 与Component`

    React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实
    现 shouldComponentUpdate() ,⽽而 React.PureComponent 中以浅层对⽐比 prop 和 state 的⽅方式来
    实现了了该函数。
    如果赋予 React 组件相同的 props 和 state, render() 函数会渲染相同的内容,那么在某些情况下使
    ⽤用 React.PureComponent 可提高性能。

    注意
    React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层⽐比较。如果对象中
    包含复杂的数据结构,则有可能因为⽆无法检查深层的差别,产⽣生错误的⽐比对结果。仅在你的
    props 和 state 较为简单时,才使⽤用 React.PureComponent ,或者在深层数据结构发⽣生变化时
    调⽤用 forceUpdate() 来确保组件被正确地更更新。你也可以考虑使⽤用 immutable 对象加速嵌套

    数据的⽐比较。
    此外, React.PureComponent 中的 shouldComponentUpdate() 将跳过所有⼦子组件树的 prop
    更更新。因此,请确保所有⼦子组件也都是“纯”的组件

    ![1614324509305](C:UsersanatkhAppDataRoamingTypora ypora-user-images1614324509305.png)

    ![1614324520764](C:UsersanatkhAppDataRoamingTypora ypora-user-images1614324520764.png)

    ## 认识Hook

    ### 认识Hook

    Hook 是什什么? Hook 是⼀一个特殊的函数,它可以让你“钩⼊入” React 的特性。例例如, useState 是允许
    你在 React 函数组件中添加 state 的 Hook。
    什什么时候我会⽤用 Hook? 如果你在编写函数组件并意识到需要向其添加⼀一些 state,以前的做法是必须
    将其它转化为 class。现在你可以在现有的函数组件中使⽤用 Hook。

    ```javascript
    import React, { useState } from "react";
    export default function HookPage(props) {
    // 声明⼀一个叫 “count” 的 state 变量量,初始化为0
    const [count, setCount] = useState(0);
    return (
    <div>
    <h3>HookPage</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    </div>
    );
    }
    ```

    ### 使用 Effect Hook

    Effect Hook 可以让你在函数组件中执⾏行行副作⽤用操作。
    数据获取,设置订阅以及⼿手动更更改 React 组件中的 DOM 都属于副作⽤用。不不管你知不不知道这些操作,或是“副作⽤用”这个名字,应该都在组件中使⽤用过它们。

    ```javascript
    import React, { useState, useEffect } from "react";
    export default function HookPage(props) {
    // 声明⼀一个叫 “count” 的 state 变量量,初始化为0
    const [count, setCount] = useState(0);
    // 与 componentDidMount 和 componentDidUpdate相似
    useEffect(() => {
    // 更更新 title
    document.title = `You clicked ${count} times`;
    });
    return (
    <div>
    <h3>HookPage</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    </div>
    );
    }
    ```

    在函数组件主体内(这⾥里里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器器、记录⽇日志以及执
    ⾏行行其他包含副作⽤用的操作都是不不被允许的,因为这可能会产⽣生莫名其妙的 bug 并破坏 UI 的⼀一致性。
    使⽤用 useEffect 完成副作⽤用操作。赋值给 useEffect 的函数会在组件渲染到屏幕之后执⾏行行。你可以
    把 effect 看作从 React 的纯函数式世界通往命令式世界的逃生通道。

    默认情况下, effect 将在每轮渲染结束后执⾏行行,但你可以选择让它 在只有某些值改变的时候 才执⾏行行。

    ### effect 的条件执行

    默认情况下, effect 会在每轮组件渲染完成后执⾏行行。这样的话,⼀一旦 effect 的依赖发⽣生变化,它就会被
    重新创建。
    然⽽而,在某些场景下这么做可能会矫枉过正。⽐比如,在上⼀一章节的订阅示例例中,我们不不需要在每次组件
    更更新时都创建新的订阅,⽽而是仅需要在 source props 改变时重新创建。
    要实现这⼀一点,可以给 useEffect 传递第⼆二个参数,它是 effect 所依赖的值数组。更更新后的示例例如
    下:

    ```javascript
    import React, { useState, useEffect } from "react";
    export default function HookPage(props) {
    // 声明⼀一个叫 “count” 的 state 变量量,初始化为0
    const [count, setCount] = useState(0);
    const [date, setDate] = useState(new Date());
    // 与 componentDidMount 和 componentDidUpdate相似
    useEffect(() => {
    // 更更新 title
    document.title = `You clicked ${count} times`;
    }, [count]);
    useEffect(() => {
    const timer = setInterval(() => {
    setDate(new Date());
    }, 1000);
    }, []);
    return (
    <div>
    <h3>HookPage</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    <p>{date.toLocaleTimeString()}</p>
    </div>
    );
    }
    ```

    此时,只有当 useEffect第⼆二个参数数组⾥里里的数值 改变后才会重新创建订阅。

    ### 清除 effect

    通常,组件卸载时需要清除 effect 创建的诸如订阅或计时器器 ID 等资源。要实现这⼀一点, useEffect
    函数需返回⼀一个清除函数,以防⽌止内存泄漏漏,清除函数会在组件卸载前执⾏行行。

    ```javascript
    useEffect(() => {
    const timer = setInterval(() => {
    setDate(new Date());
    }, 1000);
    return () => clearInterval(timer);
    }, []);
    ```

    ## 自定义Hook与Hook使用规则

    ### 自定义Hook

    有时候我们会想要在组件之间重⽤用⼀一些状态逻辑。⽬目前为⽌止,有两种主流⽅方案来解决这个问题: ⾼高阶组件和 render props。⾃自定义 Hook 可以让你在不不增加组件的情况下达到同样的⽬目的。
    ⾃自定义 Hook 是⼀一个函数,其名称以 “use” 开头,函数内部可以调⽤用其他的 Hook

    ```javascript
    import React, { useState, useEffect, useMemo } from "react";
    export default function CustomHookPage(props) {
    //定义⼀一个叫count的state变量量,初始化为0
    const [count, setCount] = useState(0);
    //和didMount、 didUpdate类似
    useEffect(() => {
    console.log("count effect");
    // 只需要在count发⽣生改变的时候执⾏行行就可以啦
    document.title = `点击了了${count}次`;
    }, [count]);
    return (
    <div>
    <h3>⾃自定义Hook</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    <p>{useClock().toLocaleTimeString()}</p>
    </div>
    );
    }
    //⾃自定义hook,命名必须以use开头
    function useClock() {
    const [date, setDate] = useState(new Date());
    useEffect(() => {
    console.log("date effect");
    //只需要在didMount时候执⾏行行就可以了了
    const timer = setInterval(() => {
    setDate(new Date());
    }, 1000);
    //清除定时器器,类似willUnmount
    return () => clearInterval(timer);
    }, []);
    return date;
    }<h3>⾃自定义Hook</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    <p>{useClock().toLocaleTimeString()}</p>
    </div>
    );
    }
    //⾃自定义hook,命名必须以use开头
    function useClock() {
    const [date, setDate] = useState(new Date());
    useEffect(() => {
    console.log("date effect");
    //只需要在didMount时候执⾏行行就可以了了
    const timer = setInterval(() => {
    setDate(new Date());
    }, 1000);
    //清除定时器器,类似willUnmount
    return () => clearInterval(timer);
    }, []);
    return date;
    }
    ```

    ### Hook 使用规则

    Hook 就是 JavaScript 函数,但是使⽤用它们会有两个额外的规则:
    只能在函数最外层调⽤用 Hook。不不要在循环、条件判断或者⼦子函数中调⽤用。
    只能在 React 的函数组件中调⽤用 Hook。不不要在其他 JavaScript 函数中调⽤用。(还有⼀一个地⽅方可
    以调⽤用 Hook —— 就是⾃自定义的 Hook 中。)

    ## Hook API之useMemo与useCallback

    ### useMemo

    把“创建”函数和依赖项数组作为参数传⼊入 useMemo ,它仅会在某个依赖项改变时才重新计算
    memoized 值。这种优化有助于避免在每次渲染时都进⾏行行⾼高开销的计算。

    ```javascript
    import React, { useState, useMemo } from "react";
    export default function UseMemoPage(props) {
    const [count, setCount] = useState(0);
    const expensive = useMemo(() => {
    console.log("compute");
    let sum = 0;
    for (let i = 0; i < count; i++) {
    sum += i;
    }
    return sum;
    //只有count变化,这⾥里里才重新执⾏行行
    }, [count]);
    const [value, setValue] = useState("");
    return (
    <div>
    <h3>UseMemoPage</h3>
    <p>expensive:{expensive}</p>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    <input value={value} onChange={event => setValue(event.target.value)} />
    </div>
    );
    }
    ```

    ### useCallback

    把内联回调函数及依赖项数组作为参数传⼊入 useCallback ,它将返回该回调函数的 memoized 版本,
    该回调函数仅在某个依赖项改变时才会更更新。当你把回调函数传递给经过优化的并使⽤用引⽤用相等性去避
    免⾮非必要渲染(例例如 shouldComponentUpdate )的⼦子组件时,它将⾮非常有⽤用。

    ```javascript
    import React, { useState, useCallback, PureComponent } from "react";
    export default function UseCallbackPage(props) {
    const [count, setCount] = useState(0);
    const addClick = useCallback(() => {
    let sum = 0;
    for (let i = 0; i < count; i++) {
    sum += i;
    }
    return sum;
    }, [count]);
    const [value, setValue] = useState("");
    return (
    <div>
    <h3>UseCallbackPage</h3>
    <p>{count}</p>
    <button onClick={() => setCount(count + 1)}>add</button>
    <input value={value} onChange={event => setValue(event.target.value)} />
    <Child addClick={addClick} />
    </div>
    );
    }
    class Child extends PureComponent {
    render() {
    console.log("child render");
    const { addClick } = this.props;
    return (
    <div>
    <h3>Child</h3>
    <button onClick={() => console.log(addClick())}>add</button>
    </div>
    );
    }
    }
    ```

    注意
    依赖项数组不不会作为参数传给“创建”函数。虽然从概念上来说它表现为:所有“创建”函数中引⽤用的
    值都应该出现在依赖项数组中。未来编译器器会更更加智能,届时⾃自动创建数组将成为可能

  • 相关阅读:
    次短路
    【学习笔记】Git工具clone异常
    【学习笔记】 UOS安装MySQL
    AcWing 327. 玉米田(状态压缩动态规划)
    我发现了个 Python 黑魔法,执行任意代码都会自动念上一段 『平安经』
    redis主从复制-密码问题
    java远程连接服务器端的redis
    组态王历史趋势图的一些问题
    使用 autofac 实现 asp .net core 的属性注入
    从一切皆数据与计算的角度,理解进程与线程
  • 原文地址:https://www.cnblogs.com/anatkh/p/14452999.html
Copyright © 2020-2023  润新知