React-HOOK——React中类似于vue中的插槽、自定义HOOK、插槽和自定义HOOK配合使用、useReducer

目录

一、React中类似于vue中的插槽

二、自定义HOOK

三、插槽和自定义HOOK配合使用

四、useReducer

1.useReducer引入

2.语法:

3.案例:

4.useReducer +useContext实现redux

5.useReducer vs useState(面试)


一、React中类似于vue中的插槽

App.jsx:

import React,{useState} from 'react'
import Box from "./Box.jsx"
import Box2 from "./Box2.jsx"
import useTool1 from './useTool1.jsx'
export default function App() {
  let [title,changetitle]=useState("app-title")
  let Login=useTool1(123)
  return (
    <div>
      <h1>app</h1>
      <Box mysrc="helloimg1" mytitle={title}> 
         <h2>666</h2>
      </Box>
      <Box mysrc="helloimg2" mytitle="title2">
        <Box2></Box2>
      </Box>
    </div>
  )
}

Box.jsx:

import React,{useEffect} from 'react'
export default function Box(props) {
  useEffect(()=>{
    console.log(props)
  },[])
  return (
    <div>
        <h1>box-{props.mysrc}--{props.mytitle}</h1>
        {props.children}
    </div>
  )
}

Box2.jsx

import React from 'react'
export default function Box2() {
  return (
    <div>Box2</div>
  )
}

会显示:

二、自定义HOOK

HOOK使用场景:use开头的那些官方提供的HOOK函数,只能在函数组件(返回值是一个模板,且必须有一个根节点)中,或者自定义HOOK的函数中,不能在类或者普通时间函数中使用。

自定义HOOK:就是利用官方提供的HOOK来实现自己的一个具有业务功能的函数,它的特点就是使用后返回一个组件,这个思想就是类组件中的高阶组件

函数组件和自定义HOOK:组件返回模板,HOOK返回组件

App.jsx

import React,{useState} from 'react'
import Box from "./Box.jsx"
import Box2 from "./Box2.jsx"
import useTool1 from './useTool1.jsx'
export default function App() {
  let [title,changetitle]=useState("app-title")
  let Login=useTool1(123)
  return (
    <div>
      <Login></Login>
      <h1>app</h1>
      <Box mysrc="helloimg1" mytitle={title}> 
         <h2>666</h2>
      </Box>
      <Box mysrc="helloimg2" mytitle="title2">
        <Box2></Box2>
      </Box>
    </div>
  )
}

自定义HOOK:useTool1

import React, { useState, useMemo } from 'react'
function useTool1(id) {
    let [flag, setflag] = useState(true)
    let isLogin = useMemo(() => {
        let res = false//假装用id网络请求后端
        setflag(res)
        return flag
    }, [id])
    if (isLogin) {
        return function () {
            return (<div>
                用户名:假数据
            </div>)
        }
    } else {
        return function () {
            return (<div>
                <a href="#">登录</a>
            </div>)
        }
    }
}
export default useTool1;

三、插槽和自定义HOOK配合使用

App.jsx

import React from 'react'
import ctx from './Myprovider'
export default function App() {
  let Myprovider=ctx()
  return (
    <Myprovider>
        <Box2></Box2>
    </Myprovider>
  )
}

Myprovider.jsx

import React,{useState} from 'react'
export default function Myprovider() {
    let [msg,setMsg]=useState({msg:"hello"})
    function Box(props){
        return(<div>
            <h1>box</h1>
            {props.children}            
        </div>)
    }
    return Box
}

四、useReducer

1.useReducer引入

useReducer用最简单的话来说就是允许我们在函数组件里面像使用redux一样通过reducer和action来管理我们组件状态的变换

2.语法:

const [state, dispatch] = useReducer(reducer, initialArg, init?)

useReducer和useState类似,都是用来管理组件状态的

只不过和useState的setState不一样的是==>

useReducer返回的dispatch函数是用来触发某些改变state的action而不是直接设置state的值,至于不同的action如何产生新的state的值则在reducer里面定义。

useReducer接收的三个参数分别是:                            
reducer:

这是一个函数,它的签名是(currentState, action) => newState,从它的函数签名可以看出它会接收当前的state和当前dispatch的action为参数,然后返回下一个state,也就是说它负责状态转换的工作。
initialArg:

如果调用者没有提供第三个init参数,这个参数代表的是这个reducer的初始状态,如果init参数有被指定的话,initialArg会被作为参数传进init函数来生成初始状态。
init:

这是一个用来生成初始状态的函数,它的函数签名是(initialArg) => initialState,从它的函数签名可以看出它会接收useReducer的第二个参数initialArg作为参数,并生成一个初始状态initialState

3.案例:

App.jsx

import React,{useState,useReducer} from 'react'
export default function App() {
  let [count,setCount]=useState(10)
  let reducer=(initSate,action)=>{
    if(action.type=="MSG"){
      initSate.msg=action.value
    }
    initSate=JSON.parse(JSON.stringify(initSate))
    return initSate
  }
  let [state,dispatch]=useReducer(reducer,{msg:"hello"})
  console.log(state)
  return (
    <div>
      <h1>App</h1>
      <p>{count}</p>
      <button onClick={()=>{setCount(count+1)}}>用户交互修改count</button>
      <hr />
      <p>{state.msg}</p>
      <button onClick={()=>{dispatch({type:"MSG",value:"修改了msg数据"})}}>修改仓库msg</button>
    </div>
  )
}

4.useReducer +useContext实现redux

1)例子1

import React from "react"
let context1=React.createContext(null)
export default context1
import { useRef, useEffect, useCallback, useState, useMemo, useReducer } from 'react'
import Mycontext from "./MyContext.jsx"
import Mybox2 from "./Mybox2.jsx"
function Mybox() {
    let [state,dispach]=useReducer((state,action)=>{
        
        if(action.type=="msg"){
          
            state.msg= action.value
        }
        else if(action.type=="age"){
            state.age= action.value
        }
        console.log(state)
        return JSON.parse(JSON.stringify(state))
       
    },{msg:"hello",age:18})
   
    // useReducer+useContext ==>做出redux框架的功能(全局数据共享)
    //1.给根组件生成一个数据容器(不是用useState生成的,是用useReducer)
    //2.把这个数据容器(是一个hook容器)传给子代组件使用,使用的技术是useContext
    return (
        <Mycontext.Provider value={[state,dispach]}>
            <h1>1</h1>
            <p>{state.msg}</p>
            <Mybox2></Mybox2>
        </Mycontext.Provider>
    )
}

export default Mybox
import {useReducer,useContext} from 'react'
import context1 from "./MyContext.jsx"
import MyBox3 from "./MyBox3.jsx"
export default function Mybox2() {
  const [state,dispacth] = useContext(context1)
  console.log(state);
  let fn=()=>{
      console.log(6666)
    dispacth({type:"msg",value:"1234567"})
  }
    return (
        <div>
            <h1>2</h1>
            <p>{state.msg}</p>
            <button onClick={fn}>修改</button>
            <MyBox3></MyBox3>
          

        </div>
    )
}
import React,{useContext} from 'react'
import context2 from "./MyContext.jsx"

export default function Mybox3() {
    let [state,dispacth]=useContext(context2)
    return (
        <div>
            <h1>3</h1>
            <p>{state.msg}</p>
            
        </div>
    )
}

2) 例子2

src/store/index.jsx

import React, { useReducer } from 'react'
import ctx from "./store"
export default function Myredux(props) {
  let reducer = (state, action) => {
    if (action.type == "MSG") {
      state.msg = action.value
    }
    if (action.type == "TOKEN") {
      state.token = action.value
    }
    state = JSON.parse(JSON.stringify(state))
    return state
  }
  let [store, dispatch] = useReducer(reducer, { msg: "hello", token: "af123123" }, function (arg) {
    //可以处理数据 然后返回值作为仓库的初始状态
    arg.msg = "123"
    return arg
  })
  return (
    <ctx.Provider value={[store, dispatch]}>
      {props.children}
    </ctx.Provider>
  )
}

src/store/store.jsx

import React from 'react'
let ctx=React.createContext(null)
export default ctx;

App.jsx

import React,{useContext} from 'react'
import ctx from "./store/store"
import Box from './Box.jsx'
export default function App() {
  let [store,dispatch]=useContext(ctx)
  console.log(store,66661)
  return (
    <div>
      <h1>App</h1>
      {/* <p>{obj.msg}</p> */}
      <p>App--{store.msg}</p>
      <button onClick={()=>{dispatch({type:'MSG',value:"666app修改了仓库"})}}>change</button>
      <Box></Box>
    </div>
  )
}

Box.jsx

import React,{useContext} from 'react'
import store from "./store/store"
import Box2 from './Box2.jsx'
export default function Box() {
  let [state,dispatch]=useContext(store)
  return (
    <div>
        <h1>Box--{state.msg}</h1>
        <button onClick={()=>{dispatch({type:"MSG",value:"box修改了仓库"})}}>box修改仓库</button>
        <Box2></Box2>
    </div>
  )
}

Box2.jsx

import React,{useContext} from 'react'
import Store from "./store/store"
export default function Box2() {
    let [state,dispatch]=useContext(Store)
  return (
    <div>Box2--{state.msg}</div>
  )
}

5.useReducer vs useState(面试)

useReducer和useState都可以用来管理组件的状态,它们之间最大的区别就是,useReducer将状态和状态的变化统一管理在reducer函数里面,这样对于一些复杂的状态管理会十分方便我们debug,因为它对状态的改变是封闭的。而由于useState返回的setState可以直接在任意地方设置我们状态的值,当我们组件的状态转换逻辑十分复杂时,它将很难debug,因为它是开放的状态管理。总体的来说,在useReducer和useState如何进行选择的问题上我们可以参考以下这些原则:

  • useState情况使用

    ​
    - state的值是JS原始数据类型,如number, string和boolean等
    - state的转换逻辑十分简单
    - 组件内不同的状态是没有关联的,它们可以使用多个独立的useState来单独管理
    
  • useReducer情况使用

    - state的值是object或者array
    - state的转换逻辑十分复杂, 需要使用reducer函数来统一管理
    - 组件内多个state互相关联,改变一个状态时也需要改变另一个,放在同一个state内使用reducer来统一管理
    - 状态定义在父级组件,不过需要在深层次嵌套的子组件中使用和改变父组件的状态,可以同时使用useReducer和useContext两个hook,将dispatch方法放进context里面来避免组件的props drilling
    - 如果你希望你的状态管理是可预测的和可维护的,请useReducer
    - 如果你希望你的状态变化可以被测试,请使用useReducer
    

猜你喜欢

转载自blog.csdn.net/qq_52301431/article/details/127365976