一、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。
九、高阶组件
含义:函数调用后返回了一个组件,这个函数就是高阶组件