React04:hooks

hooks 钩子函数

  • 用于解决 函数式组件没有办法定义 state 和 生命周期的问题。
  • hooks 主要用于解决 类组件进行逻辑复用极其麻烦的问题
  • hooks 本质就是函数
  • 所有的hooks命名规定以use开头

useState 定义状态

let [状态,修改该状态的方法] = useState(初始值);

  1. 在同一个组件中可以使用 useState 定义多个状态
  2. 注意 useState 返回的 setState 方法,不会进行对象合并,需要自己将原先属性再传递一次...data
  3. 注意 useState 返回的 setState 方法同样是异步方法
function App(props) {
    // let [count, setCount] = useState(0)
    let [data, setData] = useState({
        name: "小明",
        count: 0
    });
    let { count, name } = data;
    return <div>
        <p>{count}</p>
        <button onClick={() => {
            setData({
                ...data,
                count: ++count
            });

        }}>递增</button>
        <br />
        <input
            type="text"
            value={name}
            onChange={({ target }) => {
                setData({
                    ...data,
                    name: target.value
                });
                console.log(name);
            }}
        />
        <p>{name}</p>
    </div>;
}

useEffect 副作用函数

生命周期函数:在生命周期函数中通常处理:将数据进行请求或者获取原生dom进行操作

  1. 不写依赖参数,该useEffect,会在组件挂载完及更新完之后都会执行
  2. 如果依赖参数为空数组,该useEffect,只会在挂载完之后执行,并在组件即将卸载时,执行该useEffect的返回函数
  3. 有依赖参数时,该useEffect,会在挂载完之后执行,以及依赖参数有变化时执行
useEffect(() => {
	副作用要处理的事情
	return () => {
		副作用的回调函数
	}
}, [依赖参数])

依赖参数

不写依赖参数时,该effect会在组件生命周期挂载完以及更新完之后都会执行

import React, { useState, useEffect } from "react";

function App(props) {
    let [data, setData] = useState({
        name: "小明",
        count: 0
    });
    useEffect(() => {
        console.log("挂载完成或更新完成");
    });
    let { count, name } = data;
    return <div>
        <p>{count}</p>
        <button onClick={() => {
            setData({
                ...data,
                count: ++count
            });

        }}>递增</button>
    </div>;
}

export default App;

传入依赖参数为空数组时,只会在挂载完成之后执行

import React, { useState, useEffect } from "react";

function App(props) {
    let [data, setData] = useState({
        name: "小明",
        count: 0
    });
    useEffect(() => {
        console.log("挂载完成或更新完成");
    });
    useEffect(() => {
        console.log("挂载完成之后执行");
    }, []);
	// ...
}

export default App;

只在更新完成之后执行的方法

let isMount = false;
function App(props) {
	// ...
    useEffect(() => {
        if (isMount) {
            console.log("更新完成之后执行");
        }
        isMount = true;
    });
	// ...
    </div>;
}

有依赖参数时,该useEffect会在挂载完成后以及依赖参数有变化时执行

    useEffect(() => {
        console.log("count改变了");
    }, [count]);

副作用函数中的回调函数

useEffect(() => {
    console.log("副作用函数");
    return () => {
        console.log("回调函数");
    };
});
  • 挂载阶段:组件挂载—副作用函数
  • 更新阶段:
    1. 组件更新生成虚拟DOM
    2. 回调函数
    3. 组件更新完成
    4. 副作用函数

在这里插入图片描述
传入依赖参数为空数组时,会在挂载完成之后执行副作用函数,并且会在组件即将卸载时执行副总用函数中的回调函数

    useEffect(() => {
        console.log("副作用函数:组件挂载或更新完成");
        return () => {
            console.log("返还函数:即将卸载");
        };
    },[]);

所以返还函数用的最多的地方就是检测组件即将卸载

对应react的生命周期

不写参数时,对应挂载后和组件更新后

componentDidMount(){
    console.log("组件挂载完毕");
}
componentDidUpdate(){
    console.log("组件更新完毕");
}

写空数组时,只对应挂载后

componentDidMount(){
    console.log("组件挂载完毕");
}

数组中写参数时,对应挂载后以及依赖参数有改变时执行

Effect中有返回函数时,返回函数执行对应卸载前

componentWillUnmount(){
    console.log("组件即将卸载");
}

useRef

  • 用于关联原生DOM节点
    • 直接绑定,如果过DOM节点有修改,React会同步ref的值
  • 使用ref来记录组件更新前的一些数据
function Child(props) {
    let [data, setData] = useState({
        name: "小明",
        count: 0
    });
    let { count, name } = data;
    let prevCount = useRef(count);	// 状态更新了,ref并不会更新
    let countP = useRef();
    useEffect(() => {
        console.log(count, countP.current, prevCount);

    });
    return (
        <div>
            <p ref={countP}>{count}</p>
            <button onClick={() => {
                setData({
                    ...data,
                    count: ++count
                });

            }}>递增</button>
			// ...
        </div>
    );
}

在这里插入图片描述

如果ref中存储的是值,则需要手动更新

    useEffect(() => {
        prevCount.current = count
        console.log(count, countP.current, prevCount);
    });

在这里插入图片描述

通过 useRef 存储值来判断挂载与更新

    let { count, name } = data;
    let prevCount = useRef(count);
    let initCount = useRef(count);
    let initName = useRef(name);
    let countP = useRef();
    useEffect(() => {
        prevCount.current = count;
        console.log(count, countP.current, prevCount);
    }, [count]);

    useEffect(() => {
        if (initCount.current === count && initName.current === name) {
            console.log("挂载完成");
        } else {
            console.log("更新完成");
        }
    }, [count, name]);

在这里插入图片描述

useMemo

  • 写法类似于useEffect,功能类似于vue中的计算属性
  • 监听依赖参数的改变,返回新的数据
  • 依赖参数也可以限定条件,不满足条件就不会执行
let age2 = useMemo(()=>{
    console.log(1);
    return age < 18?"未成年":"成年人";
},[age < 18]);

useCallback

  • 是useMemo的变形
  • 当useMemo中需要一个返回函数,在外部按需加载时,逻辑可能就会很复杂
  • useCallback就整合了这个返回函数
let age2 = useMemo(()=>{
    return ()=>age<18?"未成年":"成年人";
},[age < 18]);
let age2 = useCallback(()=>age<18?"未成年":"成年人",[age < 18]);

return <div>年龄阶段:{age2()}</div>

useContext

类组件中的context

  • createContext
    • Provider
    • Consumer
  • contextType

在类组件中,createContext用于跨层传递信息

使用<Provider>组件包裹父级,并传递数据,那么包裹下的所有层级都能拿到这个数据

import React, {Component,createContext, useContext} from 'react';
let {Provider,Consumer} = createContext();
class Context extends Component {
   render(){
       return <div>
            <myContext.Provider value={{info :"今天天气不错"}}>
                <Parent />
            </myContext.Provider>
       </div>
   }
}

通过<Consumer>包裹子级来让子级接收数据

class Child extends Component {
    render(){
        return (
          <Consumer>
              {(context)=>{
                  console.log(context);
                  return <strong>这是祖先传下来的宝贝:{context.info} </strong>
              }}
           </Consumer>
        )
    }
}

简易方写法,静态static contextType = myContext;

let myContext = createContext();
class Child extends Component {
    static contextType = myContext;
    render(){
        console.log(this.context);
        return (
            <strong>这是祖先传下来的宝贝: {this.context.info}</strong>
        )
    }
}

函数式组件中的useContext

useContext(myContext)

let myContext = createContext();
function Child2(){
    let {info, dispatch} = useContext(myContext);
    return (
        <div><strong>这是祖先传下来的宝贝: {info} </strong></div>
    )
}

useReducer

自定义hooks

把重复使用的逻辑抽离封装成hooks

import React, { useState, useEffect, Fragment } from 'react';
// 将重复使用的逻辑抽离出来,定义成hooks
function useScrollY() {
    console.log(window.scrollY)
    let [scrollY, setScrollY] = useState(window.scrollY);
    // 组件卸载时通过useEffect的返还函数清除挂载的全局事件
    useEffect(() => {
        return () => {
            window.onscroll = null;
        };
    }, []);
    window.onscroll = function () {
        setScrollY(window.scrollY);
    };
    return [scrollY, (newScrollY) => {
        window.scrollTo(0, newScrollY);
        // setScrollY(newScrollY);
    }];
}
function App() {
    let [scrollY, setScrollY] = useScrollY();
    return (
        <Fragment>
            <style>
                {
                    `
                div {
                    width: 200px;
                    height: 400px;
                    font: 100px/200px "宋体";
                    text-align: center;
                    border: 2px solid #000; 
                }
                span {
                    position:absolute;
                    left: 0;
                    top: 200px;
                    width: 100px;
                    font: 16px/2 "宋体";
                    background: #999;
                    color: #fff;
                }
            `
                }
            </style>
            <div>1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
            <div>6</div>
            <div>7</div>
            <span
                style={{
                    top: 200 + scrollY
                }}
                onClick={() => {
                    setScrollY(0);
                }}
            >{scrollY}</span>
        </Fragment>
    );
}
export default App;

hooks优势

  • 简化组件逻辑
  • 复用状态逻辑
  • 无需使用类组件编写

Hook 使用规则

  • 命名以use开头
  • 只在 React 函数中调用 Hook
    • React 函数组件中
    • React Hook 中
  • 只在最顶层使用 Hook , 比如不能在for循环里使用,不能包其他上下文
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值