react-redux-hooks的学习笔记

238 阅读16分钟

1.redux

什么是redux

  1. 作用:集中式管理react应用中多个组件共享的状态

什么情况下需要使用它

  1. 某个组件的状态需要让其他组件也能拿到
  1. 一个组件需要改变另一个组件的状态(通信)
  1. 总体原则:能不用就不用,如果不用比较吃力,就可以使用

//redux--store.js
//// 创建一个包含应用程序 state 的 Redux store实例 并暴露出去。
// 它的 API 有 { subscribe, dispatch, getState }.
import countReducer from './count_reducers'
import { createStore } from 'redux'
const store = createStore(counterReducer)
export default store

//redux--counterReducer.js
/**
 * 这是一个 reducer 函数:接受当前 state 值和描述“发生了什么”的 action 对象,
 它返回一个新的 state 值。
 * reducer 函数签名是 : (state, action) => newState
 *
 * Redux state 应该只包含普通的 JS 对象、数组和原语。
 * 根状态值通常是一个对象。 重要的是,不应该改变 state 对象,
 而是在 state 发生变化时返回一个新对象。
 *
 * 你可以在 reducer 中使用任何条件逻辑。 在这个例子中,我们使用了 switch 语句,但这不是必需的。
 * 
 */
 //counterReducer会在初始化store时,store帮我们默认调用一次 此时如果未指定 state 初始值
// undefined   type: '@@redux/INITd.r.z.j.5.i'
function counterReducer(state = { value: 0 }, action) {
  switch (action.type) {
    case 'counter/incremented':
      return { value: state.value + 1 }
    case 'counter/decremented':
      return { value: state.value - 1 }
    default:
      return state
  }
}
//store api{ subscribe, dispatch, getState }
// redux只帮助我们管理状态,自己来更新管理
// 你可以使用 subscribe() 来更新 UI 以响应 state 的更改。
// 通常你会使用视图绑定库(例如 React Redux)而不是直接使用 subscribe()。
// 可能还有其他用例对 subscribe 也有帮助。

store.subscribe(() => console.log(store.getState()))
// 改变内部状态的唯一方法是 dispatch 一个 action。
// 这些 action 可以被序列化、记录或存储,然后再重放。
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}

2.一个使用redux-count计数器

//count_actions.js
import store from "./store"

/* 此文件用来创建action对象 */
//同步action plain-object {}
/*
createIncrementedAction = (data) => { type: 'counter/incremented', data }
这样写不会return一个object,会把{}当成代码块执行
(data) =>({ type: 'counter/incremented', data })
加一个小括号就可以return 一个object
*/
const createIncrementedAction = (data) => ({ type: 'counter/incremented', data })
const createDecrementedAction = (data) => ({ type: 'counter/decremented', data })
//此对象为异步action返回值为func,在fn开启异步 ()=>{}
const createDecrementedAsyncaction = (data, delay) => {
    return () => {
        setTimeout(() => {
            store.dispatch(createIncrementedAction(data))
        }, delay);
    }
}
export { createIncrementedAction, createDecrementedAction, createDecrementedAsyncaction }
//store.js
//引入redxu中间件applyMiddleware和thunk来解决异步
//会在异步fn完成之后,创建一个{}
import {createStore,applyMiddleware} from 'redux'
import countReducer from './count_reducers'
import thunk from 'redux-thunk'
const store = createStore(countReducer,applyMiddleware(thunk))
export default store
//count_reducer.js
//此文件用来匹配action.type改变state状态,return new state
//只能接受一个plain obeject{}
export default function counterReducer(state = { value: 0 }, action) {
    
    switch (action.type) {
      case 'counter/incremented':
        return { value: state.value + action.data }
      case 'counter/decremented':
        return { value: state.value - action.data }
      default:
        return state
    }
  }
//count.js
//在组件中引入store管理状态
//store.getState拿到store中管理的state{}
//store.dispatch去派发action去更新状态
//store.subscribe(()=>{}) 订阅状态是否更新
/*
redux不会帮我们更新ui(state已经改变,ui并未更新),这里需要我们手动更新
1.在组件内 这里只要调用setState-->react就会帮我们调用renden-->更新ui视图
componentDidMount(){
store.subscribe(()=>{this.setState({})})
}
2.在入口文件 --性能问题???
const root = ReactDOM.createRoot(document.getElementById('root'));
store.subscribe(()=>{
  root.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>
  )
})
*/
import React, { Component } from 'react'
import store from '../../redux/store'
import {
  createIncrementedAction,
  createDecrementedAction,
  createDecrementedAsyncaction
} from '../../redux/cout_action'
export default class Count extends Component {
  increment = () => {
    const { value: data } = this.selectValue
    // console.log(value1);
    store.dispatch(createIncrementedAction(data * 1))
  }
  decrement = () => {
    const { value: data } = this.selectValue
    store.dispatch(createDecrementedAction(data * 1))
  }
  incrementOdd = () => {
    const { value: data } = this.selectValue
    const { value } = store.getState()
    if (value % 2 !== 0) {
      store.dispatch(createIncrementedAction(data * 1))
    }
  }
  incrementAsync = () => {
    const { value: data } = this.selectValue
    store.dispatch(createDecrementedAsyncaction(data * 1, 500))
  }
  render() {
    const { value } = store.getState()
    return (
      <div>
        <p>当前展示的值为:{value}</p>
        <select ref={c => this.selectValue = c} >
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={this.increment}>点击加1</button>
        <button onClick={this.decrement}>点击减1</button>
        <button onClick={this.incrementOdd}>点击奇数加1</button>
        <button onClick={this.incrementAsync}>点击异步加1</button>
      </div>
    )
  }
}

3.react-redux

1.什么是redux?

react-redux是一个react插件库,专门用来简化react应用中使用redux。他是从redux封装而来,因此基本原理和redux是一样的,同时存在一些差异。

React-Redux 将所有组件分成两大类:UI 组件(presentational component)和容器组件(container component)

UI组件

  • 只负责 UI 的呈现,不带有任何业务逻辑
  • 没有状态(即不使用this.state这个变量)
  • 所有数据都由参数(this.props)提供
  • 不使用任何 Redux 的 API 容器组件

容器组件

  • 负责管理数据和业务逻辑,不负责 UI 的呈现
  • 带有内部状态
  • 使用 Redux 的 API
  • UI 组件负责 UI 的呈现,容器组件负责管理数据和逻辑 React-Redux 规定,所有的 UI 组件都由用户提供,容器组件则是由 React-Redux 自动生成(由connect()函数生成)。也就是说,用户负责视觉层,状态管理则是全部交给它

这里首先展示一个完整的react-redux的使用,下面为目录结构

/*
countUI.js
1.ui组件只负责渲染ui,state等都由容器组件传递过来
2.this.props-->{stateValue,fn()}
*/
import React, { Component } from 'react'
export default class Count extends Component {
  increment = () => {
    const { value: data } = this.selectValue
    this.props.jia(data * 1)
}
  decrement = () => {
   ...
  }
  incrementOdd = () => {
   ...
  }
  incrementAsync = () => {
    const { value: data } = this.selectValue
    this.props.jiaAsync(data * 1, 500)
  }
  render() {
    const { value } = this.props.state
    return (
      <div>
        <p>当前展示的值为:{value}</p>
        <select ref={c => this.selectValue = c} >
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={this.increment}>点击加1</button>
        <button onClick={this.decrement}>点击减1</button>
        <button onClick={this.incrementOdd}>点击奇数加1</button>
        <button onClick={this.incrementAsync}>点击异步加1</button>
      </div>
    )
  }
}

容器组件

//container-count.js
import CountUI from '../../components/Count/index'
import {
    createIncreatmentAciton,
    createDecreatmentAciton,
    createDecreatmentAsyncAciton
} from '../../redux/count_action'
import { connect } from 'react-redux'
//mapStateToProps函数返回的对象中的key就作为传递给ui组件props的key,value就作为传递给ui组件props的value-状态
function mapStateToProps(state) {
    return { state }
}
//mapDispatchToProps函数返回的对象中的key就作为传递给ui组件props的key,value就作为传递给ui组件props的value-操作状态
function mapDispatchToProps(dispatch) {
    return {
        jia: (number) => {
            //通知redux执行加法
            dispatch(createIncreatmentAciton(number))
        },
        jian: (...) => {...},
        jiaAsync: (number, time) => {...}
    }
}
//这里执行connect()生成容器组件 会默认调用并且
//将参数state-->mapStateToProps, dispatch-->mapDispatchToProps,以props传递给countui
//此时 Count--countui.props
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)
//到这里就完成了ui和容器组件的功能解耦                    
//在app组件中渲染的是容器组件,中给容器COUNT组件传递store  Count---store
export default class App extends Component {
 render () {
    return (
      <div>
        {/*给容器组件传递store*/}
        <Count store={store}/>
      </div>
    )
  }}

优化react-redux代码

1.组件使用redux与store交互需要引入store,并且要手动调用store.subscript()监听store变化,此时使用react-redux的api--Provider

  • 组件:React-Redux 提供Provider组件,该组件把根组件包含起来,并且Provider组件需要传入store,这样一来所有组件都可以得到state数据
    //APP组件被包裹后,所有子组件都可以得到state数据
    <Provider store={store}>
       <App />
    </Provider>

2.合并ui和容器组件

//container-count.js
import {
    createIncreatmentAciton,
    createDecreatmentAciton,
    createDecreatmentAsyncAciton
} from '../../redux/count_action'
import { connect } from 'react-redux'
import React, { Component } from 'react'
//ui组件
class CountUI extends Component {...}
    

const mapStateToProps = (state) => ({ state })
const mapDispatchToProps = (dispatch) =>
({
    jia: (number) => { dispatch(createIncreatmentAciton(number))},
    jian: (number) => {dispatch(createDecreatmentAciton(number))},
    jiaAsync: (number, time) => {dispatch(createDecreatmentAsyncAciton(number, time))}
})
//这里执行connect() 会默认调用并且将参数state-->mapStateToProps, dispatch-->mapDispatchToProps
export default connect(mapStateToProps, mapDispatchToProps)(CountUI)

4.hooks

什么是 Hook?

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。

Hook可以多次使用,但是必须注意使用顺序。

📌 State Hook

这个例子用来显示一个计数器。当你点击按钮,计数器的值就会增加:

import React, { useState } from 'react';
function Example() {
  // 声明一个叫 “count” 的 state 变量。  const [count, setCount] = useState(0);return (<div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>);
}

(1). state Hook让函数组件也可以有state状态,并进行状态数据的读写操作

(2).语法: const [xxx,setxxx] = React.usestate(initvalue)

(3). useState() 参数:第一次初始化指定的值在内部作缓存 返回值:包含2个元素的数组,第1个为内部当前状态值,第2个为更新状态值的函数 (4).SetXxx()2种写法: setxxx(newvalue):参数为非函数值,直接指定新的状态值,内部用其覆盖原来的状态值 setXxx(value => newvalue):参数为函数,接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值

setState的参数为函数的一些注意点,函数必须return一个newValue

添加数组方法 unshift push不会返回一个newValue,即使函数return array也不会触发更新,

是因为return还是原数组,react进行的是一个浅比较,数据地址没有变化,所以不会进行视图的更新。

这里可以使用concat 还有[...data,array] 添加元素创建一个newValue来触发视图更新

⚡️ Effect Hook

useEffect给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

import React, { useState, useEffect } from 'react';
function Example() {
    const [count, setCount] = useState(0);  
// 相当于 componentDidMount 和 componentDidUpdate: 
     useEffect(() => {    
     // 使用浏览器的 API 更新页面标题    
     document.title = `You clicked ${count} times`;  });
     return (
     <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>);
}

这个钩子函数相当于类组件三个钩子函数的集合,

当你想用做componentDIdMount时,可以在第二个参数中加上[],表示谁都不监听,只会在第一次挂载时调用,这就相当于didMount函数了,

如果你想当componentDidUpdate函数用,那么你可以在第二个参数加上你要监听更新的state值,注意是数组,

如果你要当componentWillUnmount函数,则在useEffect()接收的第一个函数中返回一个函数,这个返回的函数就相当于willUnMount

//ChatAPI.subscribeToFriendStatus-->相当于componentDIdMount执行订阅
//ChatAPI.unsubscribeFromFriendStatus-->componentWillUnmount取消订阅
useEffect(() => {   
     ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);   
      return () => {      
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);         };  
     });

🍖Context Hook

这里useContext()适用于父亲向后代(父-子props)通信

React Api 实现useContext

🚗创建父组件的上下文

const ThemeContext = React.createContext(themes.light);

🚓用Provider包裹后代 value交出数据

<ThemeContext.Provider value={themes.dark} > ...</>

后代组件读取数据:

类组件读取数据

🚙声明接牧contextthis.context

static contextType = ThemeContext

🚑读取context中的value数据

this.context

🚚第二种方式:函数组件与类组件都可以

<ThemeContext .consumer>

{ value =>() } // value就是context中的value数据要显示的内容

<ThemeContext.Consumer>

这里useContext()只是封装了读取

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee"},
  dark: {
    foreground: "#ffffff",
    background: "#222222"}
};
//创建一个context ThemeContext.Provider value={themes.dark} 交给后代
//注意这里只能用value={...}
const ThemeContext = React.createContext(themes.light);
function App() {
    return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>);
}
function Toolbar(props) {
    return (
        <div>
         <ThemedButton />
        </div>
      );
}
//孙代 useContext() 可直接拿到爷爷传递的数据
function ThemedButton() {
  const theme = useContext(ThemeContext); 
  return (    
      <button style={{ background: theme.background, color: theme.foreground }}>
        I am styled by theme context!    
      </button>  
  );
}

🌭Ref Hook

类组件三种使用refd的方法

  • 1.传入字符串 -->this.refs.传入的字符串格式获取对应的元素 (不建议使用,将要移除)
  getDivRef = () => {
    this.refs.mydiv //此时拿到Dom div
  }
  render() {
   return (
      <div ref="mydiv">App</div>
    )
  }
  • 2.传入一个对象 对象是通过 React.createRef() 方式创建出来的;

使用时获取到创建的对象其中有一个current属性就是对应的元素;

  • 方式三:传入一个函数 该函数会在DOM被挂载时进行回调,

这个函数会传入一个 元素对象,我们可以自己保存;

使用时,直接拿到之前保存的元素对象即可;

useRef()

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

一个常见的用例便是命令式地访问子组件:

function TextInputWithFocusButton() 
{   const inputEl = useRef(null);
    const onButtonClick = () => {
        inputEl.current.focus()// `current` 指向已挂载到 DOM 上的文本输入元素
        }
    return (<>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>);
}

5.react一些新特性

🎐1.Fragment

可以代替根标签,增强语言性,渲染时会去掉fragment,

标签内可以传递唯一的属性 key={}

<> </>也可以实现相同的效果,但是不可以传递任何的属性

6.react router

🍔v5 -- react-router总共有三种形式的库,适用于三种场景:

  • web,对应的库名叫react-router-dom
  • native ----react-router-dom
  • anywhere(哪里都可以用)react-router

1. 路由的基本使用

的最外侧包裹了一个或 监测路由的跳转行为

明确好界面中的导航区、展示区

  • 导航区的a标签改为Link标签(需要引入,link标签阻止了默认的跳转行为)
  • 展示区写Route标签进行路径的匹配(在呈现路由组件内容的位置注册路由)

👨🏫以前的版本 v5

🕵️♂️现在的版本 v6

<Route path="/about" element={}/>

<Route path="/home" element={}/>

2. 路由组件与一般组件

🌭写法不同

  • 一般组件:
  • 路由组件:

🥞 存放位置不同:

  • 一般组件:components
  • 路由组件:pages

🍠接收到的props不同:

  • 一般组件:写组件标签时传递了什么,就能收到什么
  • 路由组件:接收到三个固定的属性
history:
                        go: ƒ go(n)
                        goBack: ƒ goBack()
                        goForward: ƒ goForward()
                        push: ƒ push(path, state)
                        replace: ƒ replace(path, state)
location:
                        pathname: "/about"
                        search: ""
                        state: undefined
match:
                        params: {}
                        path: "/about"
                        url: "/about"

3.NavLink及其封装

  • NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
  • 标签体内容是一个特殊的标签属性,可以通过this.props.children获取
<NavLink className="list-group-item" to="/about">About</NavLink>
//这里标签体的内容使用children展示
<NavLink className="list-group-item" children="About" />

4. Switch

  1. 注册路由时用Switch标签包裹所有路由
  1. 通常情况下,path和component是一一对应的关系。
  1. Switch可以提高路由匹配效率(单一匹配)。
  1. 路由的匹配是按照注册路由的顺序进行的

5.Redirect重定向

一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由

具体编码:

<Switch>
        //匹配不到路由默认展示home组件,也适用于登录系统时/ ---默认跳转home页面
        <Route path="/about" component={About}/>
        <Route path="/home" component={Home}/>
        <Redirect to="/home"/>
</Switch>

6.嵌套路由(多级路由)

🥞注册子路由时要写上父路由的path值

//注册home路由的二级路由 news messages
<Switch>
        <Route path="/home/news" component={News}/>
        <Route path="/home/message" component={Message}/>
        <Redirect to="/home/news"/>
</Switch>

7. 向路由组件传递参数

  • 🍺params参数(最多)
      • 路由链接(传递参数):

      <Link to='/demo/test/tom/18'}>详情</Link>

      • 注册路由(声明接收):

      <Route path="/demo/test/:name/:age" component={Test}/>

      • 接收参数:this.props.match.params

🍗search参数

  • 路由链接(携带参数):

<Link to='/demo/test/?name=tom&age=18'}>详情</Link>

  • 注册路由(无需声明,正常注册即可):

<Route path="/demo/test" component={Test}/>

  • 接收参数:this.props.location.search

    •   备注:获取到的search是urlencoded编码(即,name=tom&age=18)字符串,需要借助querystring解析(querystring.stringify(obj), querystring.parse(str.slice(1))

🥨state参数(不同于普通组件的state属性)

  • 路由链接(携带参数):
详情
  • 注册路由(无需声明,正常注册即可):
  • 接收参数:this.props.location.state

  1. 编程式路由导航

push和replace

路由是对浏览器历史记录的操作,总共有两种操作,push(压栈)和replace(替代栈顶元素)。

默认是push模式,要想开启replace模式,则在路由连接标签中加入replace={true}或replace

借助this.prosp.history对象上的API对操作路由跳转、前进、后退,而不用路由的和,但还是要注册路由

  • this.props.history.push()
  • this.props.history.replace()
  • this.props.history.goBack()
  • this.props.history.goForward()
  • this.props.history.go()
  1. withRouter的使用

withRouter可以加工一般组件,让一般组件具备路由组件所特有的API

withRouter的返回值是一个新组件。

在一般组件中要用到路由组件的props属性时引入。

import {withRouter} from 'react-router-dom'

//withRouter加工过的header组件,具有路由的api

export default withRouter(Header)

  1. BrowserRouter与HashRouter的区别

底层原理不一样:

BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。

HashRouter使用的是URL的哈希值。

path表现形式不一样

BrowserRouter的路径中没有#,例如:localhost:3000/demo/test

HashRouter的路径包含#,例如:localhost:3000/#/demo/test

刷新后对路由state参数的影响

1)BrowserRouter没有任何影响,因为state保存在history对象中。

2)HashRouter刷新后会导致路由state参数的丢失!!!

备注: HashRouter可以用于解决一些路径错误相关的问题。

11. React Router 6 快速上手

  1. React Router 以三个不同的包发布到 npm 上,它们分别为:
  1. react-router: 路由的核心库,提供了很多的:组件、钩子。
  1. react-router-dom: 包含react-router所有内容,并添加一些专门用于 DOM 的组件,例如 等 。
  1. react-router-native: 包括react-router所有内容,并添加一些专门用于ReactNative的API,例如:等。

🥓1. 与React Router 5.x 版本相比,改变了什么?

  1. 内置组件的变化:移除 ,新增 等。
  1. 语法的变化:component={About} 变为 element={}等。
  1. 新增多个hook:useParams、useNavigate、useMatch等。

🥗 2. 与 (一对一匹配)

  • v6版本中移除了先前的,引入了新的替代者:。
  • 和 要配合使用,且必须要用包裹。
  • 相当于一个 if 语句,如果其路径与当前 URL 匹配,则呈现其对应的组件。
  • 属性用于指定:匹配时是否区分大小写(默认为 false)。
  • 当URL发生变化时, 都会查看其所有子 元素以找到最佳匹配并呈现组件 。

也可以嵌套使用,且可配合useRoutes()配置 “路由表” ,但需要通过 组件来渲染其子路由。

<Routes>
    /*path属性用于定义路径,element属性用于定义当前路径所对应的组件*/
    <Route path="/login" element={<Login />}></Route>
    /*用于定义嵌套路由,home是一级路由,对应的路径/home*/
    <Route path="home" element={<Home />}>
    /*test1 和 test2 是二级路由,对应的路径是/home/test1 或 /home/test2*/
      <Route path="test1" element={<Test/>}></Route>
      <Route path="test2" element={<Test2/>}></Route>
     </Route>
    /* Route也可以不写element属性, 这时就是用于展示嵌套的路由 
     所对应的路径是/users/xxx */
    <Route path="users">
       <Route path="xxx" element={<Demo />} />
    </Route>
</Routes>

🌯3. ---用来代替v5 redirect重定向

作用:只要组件被渲染,就会修改路径,切换视图。

replace属性用于控制跳转模式(push 或 replace,默认是push)。

import React,{useState} from 'react'
import {Navigate} from 'react-router-dom'
export default function Home() {
        const [sum,setSum] = useState(1)
        return (
             <div>
                <h3>我是Home的内容</h3>
                {/* 根据sum的值决定是否切换视图 */}
                {sum === 1 ? <h4>sum的值为{sum}</h4> : <Navigate to="/about" replace={true}/>}
                <button onClick={()=>setSum(2)}>点我将sum变为2</button>
              </div>
        )
}

🥪4. ---子路由占位符

🍪5. Hooks

🙈🙈1. useRoutes()

作用:根据路由表,动态创建和

//routes.js
import About from '../pages/About'
import Home from '../pages/Home'
import {Navigate} from 'react-router-dom'
export default [
        {
                path:'/about',
                element:<About/>
                children:[    //子路由
                    {  
                    path:'news',
                    element:<News/>
                    }
                ]
        },
        {
                path:'/home',
                element:<Home/>
        },
        {
                path:'/',
                element:<Navigate to="/about"/>
        }
]
import routes...
export default function App() {
        /*根据路由表生成对应的路由规则
        一级路由用useRoutes()和element定位,子路由用<outlet />定位 */
         const element = useRoutes(routes) 
        return (
            const element = useRoutes(routes)  
                <div>
                        ......
                  {/* 注册路由 */}
                  {element}
                  ......
                </div>
            )
            }

🙈🙈 2. useNavigate()

作用:返回一个函数用来实现编程式导航

import {useNavigate} from 'react-router-dom'
export default function Demo() {
  const navigate = useNavigate()
  const handle = () => {
    //第一种使用方式:指定具体的路径
    navigate('/login', {
      replace: false,
      state: {a:1, b:2}
    }) 
    //第二种使用方式:传入数值进行前进或后退,类似于5.x中的 history.go()方法
    navigate(-1)
  }
  return (
    <div>
      <button onClick={handle}>按钮</button>
    </div>
  )
}

🙈🙈 3. useParams()

作用:return当前匹配路由的params参数,类似于5.x中的match.params。

import React from 'react';
import { Routes, Route, useParams } from 'react-router-dom';
import User from './pages/User.jsx'
function ProfilePage() {
  // 获取URL中携带过来的params参数
  let { id } = useParams();
}
function App() {
  return (
    <Routes>
      <Route path="users/:id" element={<User />}/>
    </Routes>
  );
}

🙈🙈 4. useSearchParams(search,setSearch)

作用:用于读取和修改当前位置的 URL 中的查询字符串。

return一个包含两个值的数组,内容分别为:当前的seaech参数、更新search的函数

import {useSearchParams} ....
export default function Detail() {
        const [search,setSearch] = useSearchParams()
        const id = search.get('id')
        const title = search.get('title')
        const content = search.get('content')
        return (
                <ul>
                    <li>
                       <button onClick={()=>setSearch('id=008&title=哈哈&content=嘻嘻')}>点我更新一下收到的search参数</button>
                     </li>
                     <li>消息编号:{id}</li>
                     <li>消息标题:{title}</li>
                     <li>消息内容:{content}</li>
                </ul>
                )
}

🙈🙈5. useLocation()

作用:获取当前 location 信息,对标5.x中的路由组件的location属性。可以传递state参数

import {useLocation} ....
export default function Detail() {
const {state:{id,title,content}} = useLocation()
    /*
                {
      hash: "",
      key: "ah9nv6sz",
      pathname: "/login",
      search: "?name=zs&age=18",
      state: {a: 1, b: 2}
    }
      */
        return (
                <ul>
                        <li>消息编号:{id}</li>
                        <li>消息标题:{title}</li>
                        <li>消息内容:{content}</li>
                </ul>
        )
}

🙈🙈6. useMatch()

作用:返回当前匹配信息,对标5.x中的路由组件的match属性。

<Route path="/login/:page/:pageSize" element={<Login />}/>
<NavLink to="/login/1/10">登录</NavLink>
export default function Login() {
  const match = useMatch('/login/:x/:y')
  console.log(match) //输出match对象
  //match对象内容如下:
  /*
          {
      params: {x: '1', y: '10'}
      pathname: "/LoGin/1/10"  
      pathnameBase: "/LoGin/1/10"
      pattern: {
              path: '/login/:x/:y', 
              caseSensitive: false, 
              end: false
      }
    }
  */
  return (
          <div>
      <h1>Login</h1>
    </div>
  )
}
  1. useInRouterContext()

作用:如果组件在 的上下文中呈现,则 useInRouterContext 钩子返回 true,否则返回 false。


🙈🙈 8. useNavigationType()

作用:返回当前的导航类型(用户是如何来到当前页面的)。

返回值:POP、PUSH、REPLACE。

备注:POP是指在浏览器中直接打开了这个路由组件(刷新页面)。


🙈🙈 9. useOutlet()

作用:用来呈现当前组件中渲染的嵌套路由。

示例代码:

const result = useOutlet()

console.log(result)

// 如果嵌套路由没有挂载,则result为null

// 如果嵌套路由已经挂载,则展示嵌套的路由对象


🙈🙈 10.useResolvedPath()

作用:给定一个 URL值,解析其中的:path、search、hash值。