1.redux
什么是redux
- 作用:集中式管理react应用中多个组件共享的状态
什么情况下需要使用它
- 某个组件的状态需要让其他组件也能拿到
- 一个组件需要改变另一个组件的状态(通信)
- 总体原则:能不用就不用,如果不用比较吃力,就可以使用
//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 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 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
- 注册路由时用Switch标签包裹所有路由
- 通常情况下,path和component是一一对应的关系。
- Switch可以提高路由匹配效率(单一匹配)。
- 路由的匹配是按照注册路由的顺序进行的
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
-
编程式路由导航
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()
-
withRouter的使用
withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
withRouter的返回值是一个新组件。
在一般组件中要用到路由组件的props属性时引入。
import {withRouter} from 'react-router-dom'
//withRouter加工过的header组件,具有路由的api
export default withRouter(Header)
-
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 快速上手
- React Router 以三个不同的包发布到 npm 上,它们分别为:
- react-router: 路由的核心库,提供了很多的:组件、钩子。
- react-router-dom: 包含react-router所有内容,并添加一些专门用于 DOM 的组件,例如 等 。
- react-router-native: 包括react-router所有内容,并添加一些专门用于ReactNative的API,例如:等。
🥓1. 与React Router 5.x 版本相比,改变了什么?
- 内置组件的变化:移除 ,新增 等。
- 语法的变化:component={About} 变为 element={}等。
- 新增多个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>
)
}
- 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值。