03-react基础知识-HOOK

一、useState

二、 useEffect

三、 useCallback

四、 useMemo 

五、 useContext

        含义:useContex用于在组件中获取上层组件通过 Context 提供的数据。它可以让你跨越组件树层级来访问共享的数据,避免了通过层层传递 props 的带来的问题。

1.实现数据的跨级传递(父组件的数据可以直接传递给孙组件或者孙孙组件)

2.组件本身可以充当数据的消费者和数据的提供者

3.若要在子组件中使用父组件的过程中,修改了子组件中的数据后,父组件中使用了该变量的地方都会刷新,则在使用provider和value进行传值时,可以以数组的形式进行传递,这样子组件即可正常使用set来修改数据了(同步更新)

<Sonctx.Provider value={[sonmsg, setsonmsg]}>
                <Grandson></Grandson>
            </Sonctx.Provider>
//app上下文对象==================================================
// 1-1:=======创建appctx文件并编辑下面语句
import React from "react";
// 创建一个上下文对象
let Appctx = React.createContext({})
// 导出appctx对象
export default Appctx


//子组件的上下文对象==========================================================
import React from "react";
// 创建一个上下文对象
let Sonctx = React.createContext({})
// 导出Sonctx对象
export default Sonctx

//孙组件上下文对象==========================================================
import React from "react";
// 创建一个上下文对象
let GrandsonCtx = React.createContext({})
// 导出GrandsonCtx对象
export default GrandsonCtx



//app组件中=============================================================
import React, { useState, useCallback } from 'react'
import Son from './component/hook/01-Son.jsx'
//1-2======== 引入自己创建的Appctx上下文对象
import Appctx from './component/hook/01-app.jsx'
function App() {
  // 定义一个appmsg数据
  let [appmsg, setmsg] = useState({ name: "jack", age: 23 })
  return (
    <div>
      <h5>app组件</h5>
      <div>{appmsg.name}</div>
      {/* 1-3=======:使用provider标签和value属性来传递 父组件的appmsg数据*/}
      <Appctx.Provider value={appmsg}>
        <Son></Son>
      </Appctx.Provider>


    </div>
  )

}
export default App


//son组件中===================================================================================



import React, { useContext, useState } from 'react'
import Grandson from './02-granSon.jsx'
//1-5======: 引入appctx上下文对象
import Appctx from './01-app.jsx'
// 2-1:引入Sonctx这个上下文对象,是自己创建的
import Sonctx from './01-Sonctx.jsx'
function Son() {
    // 1-6======:引入useContext这个函数,用useContext来接收从父组件传递过来的数据进行解构赋值
    let obj = useContext(Appctx)
    console.log("son组件的obj222", obj);

    //2-2: son组件可以是消费者,也可以作为别人的数据提供者:定义一个变量sonmsg
    const [sonmsg, setsonmsg] = useState({ name: "小将", age: 26, sex: "girl" })
    return (
        <div>
            <h5>son组件</h5>
            {/* 这里即可正常使用父组件传递过来的数据 */}
            <div>{obj.name}</div>
            <div>{obj.age}</div>
            <div>son组件的值==当孙组件进行修改了sge数据,这里是否会改变======{sonmsg.age}</div>
            {/* 使用provider标签和value属性进行传递 */}
            {/*2-3: son组件给grandson组件提供数据 */}
            {/* 这里将son的数据sonmsg和setsonmsg传递给了孙组件,即可实现在孙组件中修改子组件的值了 */}
            <Sonctx.Provider value={[sonmsg, setsonmsg]}>
                <Grandson></Grandson>
            </Sonctx.Provider>

        </div>
    )
}
export default Son



//孙组件中================================================================


import React, { useContext } from 'react'
import Appctx from './01-app'
// 2-4====引入Sonctx这个上下文对象
import Sonctx from './01-Sonctx'
function Grandson() {
    // 2-5===使用usecontext来接收从son组件中传递过来的数据进行解构赋值
    let [granobj, setsonmsg] = useContext(Sonctx)
    console.log("grandson的数据::孙组件", granobj, 1111, setsonmsg);

    // 父组件可以直接将其数据传递给孙组件乃至孙孙组件
    let Apobj = useContext(Appctx)
    console.log("app传递过来的数据", Apobj);


    let change = () => {
        // 这是主流的写法,19行为深拷贝的概念,这不是标准的写法
        granobj.age = "33"
        setsonmsg(JSON.parse(JSON.stringify(granobj)))
    }
    return (
        <div>
            <h5>Grandson组件</h5>
            {/* 2-6===即可将其看作变量正常使用 */}
            <div>{granobj.name}</div>
            <div>{granobj.age}</div>
            <div>{granobj.sex}</div>

            <button onClick={change}>孙按钮</button>
        </div>
    )
}
export default Grandson


六、useReduce 

含义:和useState类似,都是用来管理组件状态的,只是useReducer返回的dispatch函数是用来改变state的action值得,而不是直接设置state的值,不同的action如何产生新的state的值是在reducer函数里面定义的。

        格式:const [state,dispatch]=usereducer(reducer,initialArg,init?)

state:当前的变量

dispatch:用于修改state的函数,类似于usestate中的set函数

reducer:一个函数,格式为:let reducer=(currentState,action)=>newState,该函数会接收当前的state和当前的dispatch中的action为参数,然后返回一个state,也就是说,reducer函数负责状态转换的工作。(可以决定如何修改state这个变量

通过当前的状态(state)和动作(action)返回修改后的新的状态的值,接收两个参数:状态值(state)和状态值(action

initialArg:state的初始值

init:把第二个参数传给了第三个函数,让这个函数处理一下,处理的结果作为初始值传递给state

import React, { useReducer } from 'react'

function App() {
  let [count, setcount] = useReducer((currentstate, action) => {
    console.log(currentstate, action);
    // count的值是return返回的值,返回为20的话,点击按钮,页面的变量为20咯,再一次点击:当前的值也就是return返回的值20,页面也就不会再刷新了
    return 20
    // 返回为action的话,传递的是最新的值,点击按钮,页面便是修改后的值:1,6,11。。。。。。。。
    // return action
    //若有第三个参数存在的话就是将第二个参数处理一下,然后将处理过的数据给state作为初始值:这里是将1交给第三个参数将其加100后给count。最后页面一加载,页面显示的是101
  }, 1, (arg) => { return arg + 100 })
  let change = () => {
    setcount(count + 5)
  }
  return (
    <div>
      <h5>app组件</h5>
      <div>{count}</div>
      <button onClick={change}>{count}</button>
    </div>
  )

}
export default App

进阶版

若该变量里面的数据比较多,对其进行修改和传递的写法

问:1.switch里面的case语句都是相似的,但为什么不直接使用下面这个写法呢

                

        上面的写法是处理好了再将处理好了再传递过去修改

下面的写法:在case里面可以写业务逻辑的,可以自己决定如何处理该数据,也就是统一来配置修改仓库的逻辑

case语句里面的修改是统一修改的逻辑代码。

2.case语句里的为什么要大写呢?

答:为了和普通的数据进行区分,不是数据,是取数据和保存数据的一个判断。

import React, { useReducer } from 'react'

function App() {
  // 1.1====让count的初始值为obj这个对象
  let obj = { name: "cup杯子", price: "14", comment: "非常好呀,下次还来" }
  // 1.2解构赋值====这里的dispatch相当于usestate的set函数
  let [count, dispatch] = useReducer(reducer, obj)

  // 1.3=========定义reducer函数:currentstate:为当前的那个状态,action传进来的最新的那个
  let reducer = (currentstate, action) => {
    console.log("当前的那个状态:", currentstate, "传进来的那个状态:", action);
    // 1.5==== 用switch进行判断,匹配是否匹配
    switch (action.type) {
      case "NAME":
        // 1.6===将新值传递给旧值:currentstate为旧值,action为新值
        currentstate.name = action.value
        break;
      case "PRICE":
        currentstate.price = action.value
        break;
      case "COMMENT":
        currentstate.comment = action.value
        break;
    }
    //1.7===== currentstate确实被修改了,但它本身是一个引用数据,属性值改变了,但属性没改,返回的还是引用数据所以页面不会刷新,需要用到深拷贝的知识点

    return JSON.parse(JSON.stringify(currentstate))
  }


  // 1.4====:通过dispatch中的type和value来实现数据修改
  let change = () => {
    dispatch({ type: "PRICE", value: "20" })
  }
  return (
    <div>
      <h5>app组件</h5>
      <div>{count.name}</div>
      <div>{count.price}</div>
      <button onClick={change}>{count.price + 10}</button>

    </div>
  )

}
export default App

进阶版,将reducer函数封装到一个文件中,直接引进来使用。

将reducer封装到一个文件中,引入使用=========================================================
import { useReducer } from "react";
function usestore() {
    // 1.1====让count的初始值为obj这个对象
    let obj = { name: "cup杯子", price: "14", comment: "非常好呀,下次还来" }

    // 1.3=========定义reducer函数:currentstate:为当前的那个状态,action传进来的最新的那个
    let reducer = (currentstate, action) => {
        console.log("当前的那个状态:", currentstate, "传进来的那个状态:", action);
        // 1.5==== 用switch进行判断,匹配是否匹配
        switch (action.type) {
            case "NAME":
                // 1.6===将新值传递给旧值:currentstate为旧值,action为新值
                currentstate.name = action.value
                break;
            case "PRICE":
                currentstate.price = action.value
                break;
            case "COMMENT":
                currentstate.comment = action.value
                break;
        }
        //1.7===== currentstate确实被修改了,但它本身是一个引用数据,属性值改变了,但属性没改,返回的还是引用数据所以页面不会刷新,需要用到深拷贝的知识点

        return JSON.parse(JSON.stringify(currentstate))
    }
    // 解构赋值:将store的初始值赋值为obj这个对象
    let [store, dispatch] = useReducer(reducer, obj)
    return [store, dispatch]
}
// 导出的是自己自定义的hook
export default usestore

app组件中===================================================

import React, { useReducer } from 'react'
import Son from './component/01-son.jsx'
// 引入自己定义的storehook
import usestore from './store.jsx'
function App() {
  // 使用自定义的
  let [store, dispatch] = usestore()
  console.log(store);
  // 使用action将name的值改为海绵宝宝好杯子
  let action = { type: "NAME", value: "海绵宝宝好杯子" }
  // 点击按钮,则调用dispatch函数,
  let change = () => {
    dispatch(action)
  }

  // 现在存在一个问:app组件和son组件中都有name属性,在son组件中点击按钮将name的值改变了,son页面的值改变了,但app组件没有改变
  // 因为引进来的是一个函数,每一次调用的都是独立的结果,各各自是各自的。

  return (
    <div>
      <h5>app组件</h5>
      <div>{store.name}</div>
      <div>{store.price}</div>
      <Son></Son>
    </div>
  )

}
export default App


//son组件中===========================================================================

import React, { useReducer } from 'react'
// 引入自己定义的storehook
import usestore from '../store.jsx'
function Son() {

    let [store, dispatch] = usestore()
    console.log(store);
    // 使用action将name的值改为海绵宝宝好杯子
    let action = { type: "NAME", value: "海绵宝宝好杯子" }
    // 点击按钮,则调用dispatch函数,
    let change = () => {
        dispatch(action)
    }
    return (
        <div>
            <h5>son组件</h5>
            <div>{store.name}</div>
            <button onClick={change}>{store.name}</button>
        </div>
    )

}
export default Son


 问题:app组件和son组件中都有name属性,在son组件中点击按钮将name的值改变了,son页面的值改变了,但app组件没有改变。
          因为引进来的是一个函数,每一次调用的都是独立的结果,各各自是各自的。

所以要利用usecontext、插槽、usereducer来实现仓库

在main.jsx文件中引入刚刚封装的store

七、useRef 

八、自定义Hoook

含义将官方的hooks搭配使用设计出自己的use开头的函数,该函数具备自定义的功能,就是自定义hook。

九、高阶组件(HOC)

含义:函数调用后返回了一个组件,这个函数就是高阶组件

HOC是react中复用组件逻辑的一种高级技巧,HOC本身不是react api的一部分,只是一种基于react的组合特性而形成的一种设计模式,也就是说当调用函数后返回了一个函数,那么这个调用的那个函数就是高阶组件。


import React, { useState } from 'react'
function Son() {
    // cup这个组件返回的是一个jsx对象,所以是一个简单的组件
    function Cup() {
        let [obj, setobj] = useState({ name: "画面宝宝", price: 23, comment: "棒棒!!!" })
        return <div>
            <h5>cup这个组件</h5>
            <div>{obj.name}</div>
            <div>{obj.price}</div>
            <div>{obj.comment}</div>
        </div>
    }
    // HOC高阶组件:该函数返回的还是一个函数,
    function Phone() {
        // 返回的是cup这个函数组件,所以Phone是一个高阶组件
        return Cup()
    }
    return (
        <div>
            <h5>Son组件</h5>

            <Cup></Cup>
            <h6>phone的高阶组件</h6>
            <Phone></Phone>

        </div>
    )

}
export default Son

为什么要使用HOC高阶组件呢

        1.抽取重复的代码,实现组件的重复使用,也就是相同功能的组件重复使用

    

         2.根据条件渲染,控制组件的渲染逻辑:权限控制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值