react18全部钩子

本文详细介绍了React 18中的各种钩子函数,包括useState、useRef、React.Portal、Fragment、useContext等,并探讨了如何在实际项目中使用RTK和react-router。此外,还讲解了如何优化组件渲染,如使用React.memo和useCallback。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

useState

1、使用钩子函数useState()来创建state

import {useState} from "react"

2、它需要一个值作为参数,这个值就是state的初始值

const result=useState(1);

3、useState会返回一个数组,result就是数组,数组包含俩个元素

//第一个元素是初始值,只用来显示数据,直接修改触发不了组件的重新渲染
let counter=result[0];
//第二个元素,是一个函数,用来接受一个参数来修改state的值
let setCounter=result[1];

4、最终写法

const [state,setState]=useState(initialState);

注意事项

setState修改state的值的过程是异步过程,所以存在一个情况:假如异步的时间是一秒钟,如果在一秒里面给state设置俩次的值,并且每次的值都要根据上一次的值来,比如计数器,需要前一个值进行运算,就会出现一秒内进行俩次运算,结果可能会出错

//比如一秒内进行俩次运算
const [counter,setCounter]=useState(1);
setCounter(counter+1);
setCounter(counter+1);
//结果是2

所以这种需要利用上一次产生的值进行下一次运算的state,需要用回调函数来进行运算

setCounter(preState=>prestate+1);

useRef

获取节点有俩种方式:

  1. 获取原生的DOM对象

    const header=document.getElementById('header');
    header.innerHTML="哈哈"
    

    这种方式操作麻烦,浪费性能,不推荐

  2. 直接从React处获取DOM对象

    步骤

    1. 使用useRef()钩子函数

      import {useRef} from "react"	
      
      • React中的钩子函数只能用与函数组件或自定义钩子
      • 钩子函数只能直接在函数组件中调用
    2. 创建ref容器

      const h1Ref=useRef();
      
    3. 将DOM节点放进去

      return (
      	<h1 ref={h1Ref}>我是标题h1</h1>
      )
      
    4. 使用

      console.log(h1Ref.current);
      

React.portal传送门

如果想设置一个自定义遮罩,遮罩里面有其他组件,这个使用应该把遮罩“传送”到根节点,不然会出现poistion、overflow等等问题

这个时候,portal就出现了

使用

  1. 在index,html文件的body标签添加一个id为backdrop-root的div

    <body>
      <div id="root"></div>
      <div id="backdrop-root"></div>
    </body>
    
  2. 在自定义遮罩组件中,引入ReactDOM

    import ReactDOM from "react-dom";
    
  3. 通过DOM操作获取id为backdrop-root的节点

    const backdropRoot=documentElementById("backgrop-root")
    
  4. 包装return里的jsx元素

    //创建传送门,并指定传送节点
    return ReactDOM.createPortal(
    	<div>待渲染的html代码</div>
    ,backdropRoot)
    

Fragment

在React中,JSX必须有且只有一个根元素。这就导致了在有些情况下我们不得不在子元素的外部添加一个额外的父元素

import React from 'react';
const MyComponent = () => {
    return (
        <div>
            <div>我是组件1</div>
            <div>我是组件2</div>
            <div>我是组件3</div>
        </div>
    );
};
export default MyComponent;

解决方案:

  1. 使用Fragment

    1. 创建一个根组件

      import React from 'react';
      const MyFragment = (props) => {
          return props.children;
      };
      export default MyFragment;
      
    2. 改造MyComponent组件

      import React from 'react';
      import MyFragment from "./MyFragment";
      const MyComponent = () => {
          return (
              <MyFragment>
                  <div>我是组件1</div>
                  <div>我是组件2</div>
                  <div>我是组件3</div>
              </MyFragment>
          );
      };
      export default MyComponent;
      
  2. 使用幽灵标签改造

    import React from 'react';
    const MyComponent = () => {
        return (
            <>
                <div>我是组件1</div>
                <div>我是组件2</div>
                <div>我是组件3</div>
            </>
        );
    };
    export default MyComponent;
    

useContext提供者

在React中组件间的数据通信是通过props进行的,父组件给子组件设置props,子组件给后代组件设置props,props在组件间自上向下(父传子)的逐层传递数据。但并不是所有的数据都适合这种传递方式,有些数据需要在多个组件中共同使用,如果还通过props一层一层传递,麻烦自不必多说。

Context类似于JS中的全局作用域,可以将一些公共数据设置到一个同一个Context中,使得所有的组件都可以访问到这些数据。

  1. 创建js文件
import React from "react
const CartContext =React.createContext({
	...属性,
	...方法
})
export default CartContext;

2.设置provider提供者

在拥有数据的组件里面导入刚刚的js文件,命名为CartContext

//把要提供的数据写在value里面
<CartContext.Provider value={数据}>
	子组件
</CartContext>

3.在要使用数据的子/孙/…组件里面使用

在拥有数据的组件里面导入刚刚的js文件,命名为CartContext

import React, {useContext} from "react";
//在组件里面使用勾子函数
const ctx=useContext(CardtContext);
//调用属性
ctx.name;
//调用方法
ctx.setName(name);

4.注意事项

​ 1.组件一定要大写!!!
​ 2.value里面的值一定要对应上!!!

useEffect===>mounted

问题:由于setState会修改state的值,从而引起组件重新渲染,但如果直接把setState写到组件里面,会引起渲染次数过多的bug

import react,{useState} from "react"
const App=()=>{
	const [counter,setCounter]=useState(1);
	setState(2);
	return (
		<div>11111</div>
	)
}
export default App;

bug解释:电脑从App()开始解析,遇到setState(2),会触发App重新渲染,当再遇到setState(2),于是又开始重新渲染

解决办法:

import {useEffect} from "react";

useEffect()需要一个函数作为参数,和一个依赖数组,数组里面是手影响的所以元素

useEffect(()=>{
	//编写那些会产生副作用的代码
},[]);

setEffect()中的回调函数会在组件每次渲染完毕之后执行,这也是它和写在函数体中代码的最大的不同,函数体中的代码会在组件渲染前执行,而useEffect()中的代码是在组件渲染后才执行,这就避免了代码的执行影响到组件渲染。

import {useEffect} from "react"
useEffect(()=>{
	const timer=setTimeout(()=>{
		props.onFilter(keyword)
	},1000)

	return ()=>{
		clearTimeout(timer)
	}
},[keyword])

1、组件渲染成功后,执行useEffect,先创建timer定时器,再执行return的claerTimeout
2、当keyword发生变化时,就会执行useEffect,这样子每次执行都会清除上一个留下来的timer,再去创建一个新timer,而新timer里的过滤操作要一秒后执行
3、只要输入keyword的间隔不超过一秒,就会不断执行清除定时器创建定时器的操作,而不会执行定时器的过滤操作

useInsertionEffect===>beforeCreate

useLayoutEffect===>beforeUpdate

useReducer

在React的函数组件中,我们可以通过useState()来创建state。这种创建state的方式会给我们返回两个东西state和setState()。state用来读取数据,而setState()用来设置修改数据。但是这种方式也存在着一些不足,因为所有的修改state的方式都必须通过setState()来进行,如果遇到一些复杂度比较高的state时,这种方式似乎就变得不是那么的优雅。

遇到有多种方式修改state的state时,推荐使用useReducer

使用:

  1. 引入

    import {useReducer} from "react";
    
  2. 定义

    const [state, dispatch] = useReducer(reducer, initialArg, init);
    
  3. 解释:

    1. state:用来获取state的值
    2. dispatch:可以传参来指定怎么修改state方式
    3. reducer:有俩个参数,第一个参数是state,是state的值,第二个是action,通常用switch来接受dispatch传过来的参数来进行选择修改方式。
    4. initialArg:state的初始值
    5. init:可选。是函数,处理初始state的值

使用方式:

import {useReducer, useState} from 'react';
const reducer = (state, action) => {
    switch(action.type){
        case 'add':
            return state + 1;
        case 'sub':
            return state - 1;
    }
};

function App() {
    const [count, countDispath] = useReducer(reducer,1);
    return (
        <div className="App">
            {count}

            <div>
                <button onClick={()=>countDispath({type:'sub'})}>-</button>
                <button onClick={()=>countDispath({type:'add'})}>+</button>
            </div>
        </div>
    );
}

export default App;

React.memo阻止渲染

React组件会在两种情况下发生重新渲染。第一种,当组件自身的state发生变化时。第二种,当组件的父组件重新渲染时。

第二种情况看起来没那么必要,要是父组件数据根本影响不到子组件,那么父组件重新渲染,子组件就没必要重新渲染

所以,在特定情况阻止子组件重新渲染

使用:

​ 对子组件进行包装

const zizujian = () => {
    console.log('B渲染');
    return (
        <div>
            <h2>子组件</h2>
        </div>
    );
};
export default React.memo(zizujian);

当一个组件的父组件发生重新渲染,而子组件的props没有发生变化时,它会直接将缓存中的组件渲染结果返回而不是再次触发子组件的重新渲染,这样一来就大大的降低了子组件重新渲染的次数

useCallback–解决memo带来的问题,缓存函数

在使用memo时,父组件传递的props数据会导致memo失效,重新渲染,这是不可避免的

但是,如果父组件传递一个函数,函数又不能改变,但是父组件每次重新渲染都会渲染一个函数,从而激发传递子组件的porps,导致memo失效,这会给子组件不必要的渲染

所以,如果子组件使用了memo,父组件传递的函数应该用useCallback进行包装

import {useCallback} from "react";
const clickHandler=useCallback(()=>{
	//代码
},[依赖项])

useMemo缓存函数结果

function sum(a,b){
    return a+b
}
const App=()=>{
    let a=1
    let b=3
    const result=useMemo(()=>{
        return sum(a,b)
    },[a,b])//依赖项
}

React.forwardRef暴露ref

包装组件,使外部组件能通过ref来访问组件dom

const App=React.forwardRef((props,ref))=>{
    //ref是使用React.forwardRef之后新增的参数
}

但如果直接暴露出去,会很危险,所以要限制它,要使用useImperativeHandle

useImperativeHandle限制暴露ref

const App=React.forwardRef((props,ref))=>{
    //ref是使用React.forwardRef之后新增的参数
    useImperativeHandle(ref,()=>{
        return {
            //函数
            //属性
        }
    })
}

useDebugValue

useDeferredValue===>watch

需要一个state的作为参数,会为该state创建一个延迟值,当设置了延迟值后,每次state修改时都会触发俩次重新渲染

这俩次执行对于其他的部分没有区别,单数延迟值俩次执行的值是不同的

第一次执行时,延迟值时state的旧值,第二次执行时,延迟值时state的新值

useTransition

startTransition(()=>{//在回调函数中设置setState会等其他setState生效后才执行
	setState(11)
})

useId

生成id

redux

网页直接引用

<script src="https://unpkg.com/redux@4.2.0/dist/redux.js"></script>

演示(初稿)

const reducer=(state={count:1},action)=>{
	switch(action.type){
		case 'ADD':
			return {...state,count:count.state+=1};
		case 'SUB'
			return {...state,...state,count:count.state-=1};
		case 'ADD_N':
			return {...state,count:count.state+count.action.payload}
		default:
			return state
	}
}
const store=Redux.createStore(reducer)

store.subscribe(()=>{
	countSpan.innerText=store.getState().count
})

subBtn.addEventListener('click',()=>{
	store.dispatch({type:'SUB'})
})

改进后

RTK

React里使用RTK

npm install react-redux @reduxjs/toolkit -S

使用RTK创建store

import {createSlice} from "@reduxjs/toolkit"

//createSlice创建reducer的切片
//它需要一个配置对象作为参数,通过对象的不同的属性来指定它的配置
const stuSlice=createSlice({
    name:"stu",//用来自动生成action中的type
    initialState:{
        name:"孙悟空",
        age:18,
        gender:"男"address:"花果山"
    },//state的初始值
    reducers:{
		setName(state,action){
            //通过不同的方法来指定对state的不同操作
            //俩个参数:state 这个state是个代理对象,可以直接修改 不需要...state浅复制,直接修改
            state.name="猪八戒"
        },
        setAge(state,action){
            state.age=19
        }
    }
})
//说明
//切片对象会自动的生成action
//actions中存储的是slice自动生成的action创建器(函数),调用函数后会自动创建action对象
const {setName,setAge}=stuSlice.actions;

//{type:name/函数名,payload:函数的参数}
const nameAction=setName("哈哈");//{type:"stu/setName",payload:"哈哈"}
const ageAction=setAge(30);//{type:"stu/setName",payload:30}
//续
export const {setName,setAge}=stuSlice.actions

//创建store
const store=configureStore({
    reducer:{
        student:stuSlice.reducer
    }
})

export default store

项目使用

//index.js
import {Provider} from "react-redux"
import store from "./store"

root.render(
	<Provider store={store}>
		<App/>
	</Provider>
)
//App.js
import {useDispatch,useSelector} from "react-redux"
import {setName,setAge} from "./store"

const App=()=>{
    //useSelector()用来加载state中的数据
    const student=useSelector(state=>state.student)
    //通过useDispacth()用来获取派发器对象
    const dispacth=useDispacth();
    
    const setNameHadler=()=>{
        dispacth(setName())
    }
}

但这样子还是非常的麻烦,所以

最终使用

//store/index.js
import {configureStore} from "@reduxjs/toolkit";
import {studentReducers} from "./studentSlice";

// 创建store
const store = configureStore({
    // 这是所有的reducer
    reducer: {
        student: studentReducers
    }
})

export default store
//reducer.js
// 创建一个reducer的切片
import {createSlice} from "@reduxjs/toolkit";

const studentSlice = createSlice({
    name: "stu",//用来自动生成action中的type
    initialState: {//state的初始值
        name: "孙悟空",
        age: 18,
        gender: "男",
        address: "花果山"
    },
    reducers: {//对state的操作
        setName(state, action) {
            state.name = action.payload
        }
    }
})

export const {reducer:studentReducers}=studentSlice
export const {setName} = studentSlice.actions
//app.js
import {useDispatch, useSelector} from "react-redux";
//取别名,不然容易重名
import {setName as setStudentName} from "./store/studentSlice";

const App = () => {

    // 加载store的数据
    const student=useSelector(state=>state.student)
    // 实例化一个dispacth
    const dispacth=useDispatch()

    // 改名字
    const modfiyName=()=>{
        dispacth(setStudentName("黄达全"))
    } 
     return (
       <div>
           <span>{student.name}---</span>
      </div>
     )
  }

RTKQ

使用

RTKQ已经集成在了RTK中,如果我们已经在项目中引入了RTK则无需再引入其余的模块。如果你不想使用RTKQ给我们提供的发送请求的方式(简单封装过的fetch),你还需要引入一下你要使用的发送请求的工具。

创建api切片

RTKQ中将一组相关功能统一封装到一个Api对象中,比如:都是学生相关操作统一封装到StudentApi中,关于班级的相关操作封装到ClassApi中。

代码演示

//  ./store/studentApi.js
import {createApi,fetchBaseQuery} from "@reduxjs/toolkit/dist/query/react"

//创建Api对象-----createApi()用来创建RTKQ中的Api对象
const studentApi=createApi({
	reducerPath:'studentApi',//Api的标识,防止打包后调用时名词重复
    baseQuery:fetchBaseQuery({
        baseUrl:"http://localhost:1337/api/",
        prepareHeaders:(headers,{getState})=>{
            //获取用户的token
            const token=getState().auth.token
            if(token){
                 headers.set("Authorization",`Bearer ${token}`)
		    }
            return headers;
        }//用来统一设置请求头
    }),//指定查询的基本信息,发送请求使用的工具
    tagTypes:[{type:'student',id:'LIST'}],//用来指定Api中的标签类型
    endpoints(bulid){//endpoints用来指定Api中的各种功能,是一个方法,需要一个对象作为返回值
        //build是请求的构建器,通过bulid来设置请求的相关信息
        return {
            //查询方法
            getStudents:build.query({
                query(){
                    //返回请求地址的子路径
                    return 'student'
                },
                transformResponse(baseQueryReturnValue){//transformResponse用来转化响应数据的格式
                    return baseQueryReturnValue.data
                },
               providesTags: [{type: 'student', id: 'LIST'}]//标签生效,触发这个函数
            }),
            //根据id查询
             getStudentById:build.query({
                query(id) {
                    return `students/${id}`
                },
                transformResponse(baseQueryReturnValue) {
                    return baseQueryReturnValue.data
                },
                KeepUnusedDataFor:0,//设置数据缓存的时间,单位秒,默认60秒
                providesTags:(result,error,id)=>[{type:'student',id:id}]//回调函数来通过id触发标签
            }),
            //根据id删除数据
            delStudent:build.mutation({
                query(id){
                    return {//如果发送的不是get请求,需要返回一个对象来设置请求的信息
                        url:`student/${id}`,
                        method:"delete"
                    }
                },
                invalidatesTags: ((result, error, stu) =>
                    [{type: 'student', id: stu.id}, {type: 'student', id: 'LIST'}])
            }),
            addStudent:build.mutation({
                query(stu) {
                    return {
                        url:"students",
                        method:"post",
                        body:{data:stu}
                    }
                },
                invalidatesTags:[{type:'student',id:'LIST'}]
            })
        }
    })
})

//Api对象创建后,对象会根据各种方法自动的生成对应的钩子函数,通过这些钩子函数,可以向服务器发送请求
//由于这些钩子函数是build构建出来的,所以有一个很死板的命名规则
//获取查询student的方法:'use'+'GetStudents'+'Query',
//其中,use指的是钩子函数,GetStudents指的是api里定义的函数,Query指的是查询
export const {
    useGetStudentsQuery,
    useGetStudentById,
    useDelStudentMutation
}=studentApi

//默认导出
export default studentApi;
//  ./store/index.js
import {configureStore} from "@reduxjs/toolkit";
import studentApi from "./studentApi"

const store=configureStore({
    reducer:{
        [studentApi.reducerPath]:studentApi.reducer
    },
    //中间件
    //studentApi里有一个中间件,需要把这个中间件加入到store的中间件里面
    //而getDefaultMiddleware()返回的是一个数组,利用concat来合并数组
    middleware:getDefaultMiddleware=>getDefaultMiddleware().concat(studentApi.middleware)
})

export default store
//index.js
import ReactDOM from "react-dom/client"
import App from "./App"
import {Provider} from "react-redux"
import store from "./store"

const root=ReactDOM.createRoot(document.getElementById("root"))
root.render(
	<Provider store={store}>
    	<App/>
    </Provider>
)
// App.js
import {useGetStudentsQuery} from "./store/studentApi"

const App=()=>{
    const {data....}=useGetStudentsQuery()
    ......
}

import {useAddStudentMutation} from "../../store/studentApi" 
const [addStudentData,addResult]=useAddStudentMutation()

import {useDelStudentMutation} from "./store/studentApi";
const [delStudent,result]=useDelStudentMutation()

import {useUpdateStudentMutation} from "../../store/studentApi"
const [updateStudentData,updateResult]=useUpdateStudentMutation()

1.查询全部数据

import {useGetStudentsQuery} from "./store/studentApi";
const {data,isLoading,isSuccess}=useGetStudentsQuery()//data是请求结果

2.根据id查询数据

import {useGetStudentByIdQuery} from "../../store/studentApi"
const {isSuccess,data:inputData,isLoading}=useGetStudentByIdQuery(props.studentId)

参数解析

//useQuery()可以接受俩个参数,第二个参数可以接受一个对象,通过这个对象对请求进行配置
const result=useGetStudentsQuery(null,{
    //指定useQeury返回的结果
    selectFromResult:result=>{
        if(result.data){
            result.data=result.data.filter(item=>item.attributes.age<18)
        }
        return result
    },
    pollingInterval:0,//设置轮询的间隔,单位毫秒,如果为0则表示不轮询
    skip:false,//设置是否跳过当前请求,默认false
    refetchOnMountOrArgChange:false,//设置是否每次都重新加载数据,false正常使用缓存,true每次都重新加载数据,数字,数据换粗的时间/秒
    refetchOnFocus:true,//重回焦点
    refetchOnReconnect:false//断网连接
    //需要在./store/index.js 里设置setupListeners(store.dispacth)
})
currentData:undefined//当前参数的最新数据
data:undefined//最新的数据
isError:false//布尔值,是否有错误
error:Error()//对象,有错时才存在
isFetching:true//布尔值:数据是否在加载
isLoading:true//布尔值:数据是否第一次加载
isSuccess:false//布尔值,请求是否成功
isUninitialized:false//布尔值,请求是否还没有开始发送
refetch:f()//一个函数,用来重新加载数据
status:"pending"//字符串,请求的状态

标签总结

//api标签为
tagTypes:[{type:"student",id:"STUDENT"}]
//增
invalidatesTags:[{type:"student",id:"STUDENT"}]
//删
invalidatesTags:((result, error, id)=>[{type:"student",id},{type:"student",id:"STUDENT"}])
//改
invalidatesTags:((result, error, id)=>[{type:"student",id},{type:"student",id:"STUDENT"}])
//查询所有数据
 providesTags:[{type:"student",id:"STUDENT"}]
//根据id查询数据
providesTags:(result,error,id)=>[{type:"student",id}]

react-router5

安装

npm install react-router-dom@5 -S

yarn add react-router-dom@5

使用

//index.js
import {BrowserRouter as Router} from "react-router-dom"

root.render(
	<Router>
    	<App/>
    </Router>
)
//App.js
//1、path:映射的url地址
//2、component:要映射的组件
//3、exact:路径是否完整匹配,默认为true,不写就是false
//4、当Route的路径被访问,对应组件会自动挂载,注意:默认情况下Route并不是严格匹配,只要url地址的头部和path一致,组件就会挂载
//react-router里面,一定不要用a标签来跳转,会自动向服务器发送请求,刷新界面
<Route exact path="/" component={Home}/>
<Route exact path="/about" component={About}/>
<Link to="/">主页</Link>
<Link to="/about">about</Link>
<NavLink exact activeStyle={{}} to="/">主页</NavLink>
//HashRouter会通过url地址中的hash值来对地址进行匹配

下载nginx

下载

启动

nginx.exe
127.0.0.1

关闭

在nginx目录下,开启终端
.\nginx.exe -s stop

BrowerRouter和HashRouter

1、使用HashRouter可以直接使用nginx

2、使用BrowerRouter要改nginx配置

在conf目录下,修改nginx.conf文件
server-->loaction
#index index.html index.htm;
try_files $uri /index.html;
---------------------
在终端重新加载配置文件
.\nginx.exe -s reload

Component的props

props

match---匹配的信息
	isExact---检查路径是否完全匹配
	params ---请求的参数
		\student:id=====>\student\1  ----后面必须跟id才显示东西
location---地址信息
history---控制页面的跳转,
	push() 跳转页面
		调用:props.history.push(
			pathname:"/student",
			state:{name:"哈哈哈"}
		)
	replace()  替换页面,用新界面把就界面替换
		调用:props.history.push(
			pathname:"/student"
		)

component、render和children的区别

1、相同点:component和render都能挂载组件

2、不同点:render需要一个回调函数作为参数,回调函数返回值会被最终挂载,render不会自动传三个属性

3、children和render类似,传递回调函数,

​ 当children传递一个回调函数时,该组件无论路径是否匹配都会挂载

​ children可以传递组件

//render
<Route path="/student/:id" render={(routeProps=>{
        console.log(route.Props)//match、location、history
        return <Student name="hhh" {...routeProps}/>
    })}></Route>
//children
<Route path="/student/:id" children={(routeProps=>...routeProps)}></Route>

Prompt

跳转时询问

<Prompt when={true} message={"将要跳转页面"}/>
//message:跳转之前的提示信息
//when:是否有提示信息

Redirect

重定向

return (
    //直接访问form
	<Redirect to={"/form"}/>
    //如果从home来的,直接访问form
    <Redirect from={"/home"} to={"/form"}/>
    .....
)

react-router6

安装

npm install react-router-dom@6 -S
yarn add react-router-dom@6

使用

//index.js
import {BrowserRouter as Router} from "react-router-dom"

root.render(
	<Router>
    	<App/>
    </Router>
)
//App.js
//在router6中,移除了router5的component,render,而且children也换了作用
//挂载组件换成了element
import {Routes,Route} from "react-router-dom"
return (
	<Routes>{/*必须写Routes*/}
    	<Route path="/" element={<Home/>}></Route>
        {/*about可以不用写“/”*/}
        <Route path="about" element={<About/>}></Route>
    </Routes>
)


//menu.js
<Link to="/"></Link>
<Link to="/about"></Link>

获取参数

import {useLocation,useParams,useMatch} from "react-router-dom"

const student=()=>{
    const {id}=useParams()//通过useParams()获取参数
    const location=useLocation()//获取当前的地址信息
    const match=useMatch("/about")//检查当前url是否匹配某个路由,如果路径匹配,返回一个对象,不匹配返回一个null
    const nav=useNavigate();//获取一个用于跳转页面的函数
    
    //比如
    const clickHandler=()=>{
        nav("/home")
        nav("/home",{type:"replace"})
    }
}

路由嵌套

1、路由嵌套

//App.js
<Routes>
	<Route path="/" element={<Home/>}></Route>
    <Route path="/about" element={<About/>}>
    	<Route path="hello" element={<Hello/>}></Route>
	    <Route path="abc" element={<Abc/>}></Route>
    </Route>
    <Route path="/student:id" element={<Home/>}></Route>
</Routes>

2、出口

<Outlet/>

Navigate

//Navigate组件用来跳转指定的位置,默认使用push跳转
<Navigate to-"/student/1" repalce/>//替换页面,不留痕迹

NavLink

<NavLink style={({isActive})=>{
        return isActive?{backgroundColor:"yellow"}:null
    }} to="/student/2">学生</NavLink>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值