什么是react
React是一种用于构建用户界面的JavaScript库,它的全称是React.js。它由Facebook开发,旨在帮助开发者更高效地构建大型、高性能的Web应用程序。React通过使用虚拟DOM(Document Object Model)来实现高效的页面更新,使得开发者可以通过简单的组件化思想来构建复杂的用户界面。
react 有什么特点
1、声明式设计:当数据变动时,React能高效更新并渲染合适的组件
2、灵活 :React可以与已知的库或框架很好地配合,如Ant Design、Umi
3、高效 :React通过对DOM的模拟,最大限度地减少与DOM的交互
4、组件化: 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中
5、单项数据绑定:在React中,组件是简单且易于把握的,它们只需从父组件获取props渲染即可。如果顶层组件中的某个props改变了,React会递归的向下遍历整棵组件树,重新渲染所有使用这个属性的组件
7、JSX:避免了复杂的DOM结构,使代码利于理解和维护
声明式和命令式的区别
编程范式不同:声明式编程关注的是要做什么,而不是如何做;命令式编程关注的是如何做
代码执行方式不同:声明式代码指示JavaScript如何执行每个步骤;命令式代码每行命令指示程序如何进行下一步详细操作
工作方式不同:声明式编程中,开发人员只描述他们想要实现的目标,而无需列出使其工作的所有步骤;命令式编程中,开发人员需要详细列出每一步的工作
怎么理解react的声明式设计
React的声明式设计是指开发者只需要关注UI的状态和数据,而不需要关注具体的UI更新逻辑。通过定义组件的状态来描述UI的外观和行为,当状态发生变化时,React会根据状态的变化自动更新UI
如何使用react?
第一种cdn的方式
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
第二种 cnpm 的方式
npm install -g cnpm --registry=https://registry.npmmirror.com
npm config set registry https://registry.npmmirror.com
cnpm install -g create-react-app
create-react-app my-app
cd my-app/
npm start
什么是JSX
jsx是JavaScript的一种语法扩展,它跟模板语言很接近,但是它充分具备JavaScript的能力。JSX 是 JavaScript 的扩展,它在浏览器中并不是原生的,需要借助 Babel 这样的转译工具才能被正确执行。Babel 负责将 ES2015+ 版本的代码转换成向后兼容的 JavaScript 语法,以确保可以在不同版本的浏览器和其他环境中运行。
为什么要使用JSX
并不是强制,推荐使用
1、JSX 仅仅只是 React.createElement(component, props, …children) 函数的语法糖使用 JSX编写模板更加简单快速,代码结构更加清晰;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="test">?</div>
<!-- 核心库必须最先引入 -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 将jsx语法转成js -->
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
<script type="text/babel"> /* 一定要写babel*/ Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
// 以下是jsx语法,就是js的语法糖
const VDOM1 =
<h1>
<span>我是span</span>
</h1>
/* 以下是js语法
const VDOM2 = React.createElement('h1',{id:title},React.createElement('span',{id:title},"hello"))
*/
ReactDOM.render(VDOM1,document.getElementById('test'))
console.log(VDOM);
</script>
</body>
</html>
JSX的语法规则
1、标签里面使用js表达是要使用{},<span>我是{name}</span>
2、虚拟dom只有一个根标签
3、标签必须闭合
4、内联样式style不能等于字符串,而应该写成对象 style={{color:'red',fontSize:'30px'}}
或者把样式的对象放在外面:
let myStyle = {
foneSize:16px
}
ReactDOM.render(
<h1 style = {myStyle}>菜鸟教程</h1>,
document.getElementById('example')
);
5、标签如果是小写的就会转化成html元素,标签如果是大写的就会渲染对应的组件
6、在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。
7、样式类名指定不用写class应该写className,避开es6的class类
js中事件绑定的三种方式
<button id="test" onclick="dianwo()">dianwo</button>
<button id="test1" >dianwo</button>
<button id="test2">dianwo</button>
<script>
// 方式一
function dianwo () {
console.log(this);
}
// 方式二
const btn1 = document.getElementById('test1');
btn1.addEventListener('click',()=>{
console.log(this);
})
// 方式三
const btn2 = document.getElementById('test1');
btn2.onclick= ()=> {
console.log(this);
}
</script>
react 开发者工具的安装
首先,下载react-developer-tools开发调试工具插件
链接:https://pan.baidu.com/s/1qN9b8hglxtj1SakPhbFIGw
提取码:d4t9
--来自百度网盘超级会员V4的分享
然后右上角更多工具--拓展程序--把文件名原来的crx后缀改成zip然后拖入浏览器
就可以了
可以打开美团官网进行测试
js类方法的回顾
class Dog {
constructor (name,age) {
this.name=name;
this.age=age;
}
// 这个方法是定义在类的原型上的
speak () {
console.log(`我叫${name}`)
}
}
class Cat extends Dog {
// 如果派生类写了constructor必须要调用super方法,constructor的接收值是实例传递的参数
constructor (name,age,grade) {
super(name,age);
this.grade = grade;
}
say() {
console.log(`我读${this.grade}`);
}
}
let p2 = new Cat('tom',19,'高一');
p2.say();
总结:
1、类中的构造器不是必须写的,进行初始化操作才写
2、如果A继承了B类,并且A类写了构造器,那么A类构造器的super必须调用,并且必须写在前面
3、类中所定义的方法,都是类的原型对象上供实例去使用
类式组件
<body>
<div id="test">?</div>
<!-- 核心库必须最先引入 -->
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<!-- 将jsx语法转成js -->
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
<script type="text/babel">
const VDOM1 = <p>hhhh</p>
class MyComponent extends React.Component{
// 使用构造器来进行初始化操作,因为要设置组件实例的state状态,
// sate是用来保存组件状态的,相当于data,键值对方式。所以使用了构造器函数
constructor(props) {
super(props);
this.state = {
isHot:true
};
// 构造器外的方法都是定义在类的原型上的,通过这个方法是在实例上也添加了一个change方法
this.change = this.change.bind(this);
console.log(this); // MyComponent
console.log(this.render); // 下面定义的
}
render() {
// 点击事件和原生的onclick不一样,并且不能写onclick="change",还需要通过this获取到实例上的方法
return <h3 onClick={this.change}>今天天气很{this.state.isHot ? 'hot':'cool'}</h3>
}
change() {
// 不可以直接更改state中的数据
//this.state.isHot = !this.state.isHot; //无效
// 类中的方法开启局部的严格模式,类中的方法是给实例使用的,
// 这里this是点击事件调用的,指向的是window 返回undefined
//console.log(this); //undefined
const isHot = this.state.isHot;
this.setState({isHot:!isHot});
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test2'));
</script>
</body>
执行render函数的时候,解析组件标签
发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法。
将render返回的虚拟dom转为真实的dom,随后呈现在页面中
类的数据类型是什么
类本身是一个函数,类的示例是一个对象
class Car {};
let res =new Car();
console.log(typeof res); object
console.log(typeof Car); function
类式组件简化
可以如下方法简化:
class MyComponent extends React.Component{
赋值语句相当于直接添加在所有的实例上
state = {
isHot:true
}
render() {
return <h3 onClick={this.change}>今天天气很{this.state.isHot ? 'hot':'cool'}</h3>
}
这个change也是从原型中被添加到了实例上,但是this依然被限制了指向undefined,所以使用箭头函数就指向外层的了
change = ()=> {
const isHot = this.state.isHot;
this.setState({isHot:!isHot});
}
}
props 的使用
类式组件:
传递:ReactDOM.render(<MyComponent name='zs' age = {19 } money='33'/>,document.getElementById('test'));
接收:<li>{this.props.isWen.toUpperCase() + this.props.name + this.props.money}</li>
函数式组件接收:
function Person (props) {
const {isWen,name,money} = props;
ref的三种形式
第一种:字符串形式的ref(已经过时的ref形式,存在效率问题,不推荐使用)
class MyComponent extends React.Component {
render () {
return (
<div>
<p>请输入你的名字</p>
<input ref='name'></input>
<button onClick={this.show}>点击这里展示信息</button>
</div>
// 标签中设置ref 属性
)
}
show = ()=> {
alert(this.refs.name.value)
// 通过实例的this.refs就可以获取到对应的真实DOM
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test'));
第二种:回调形式的ref(开发用的最多的还是回调函数的形式)
ref是react内部帮我们调用的,这个ref接受的参数就是当前元素节点
<input ref={(currentNode)=>this.input1=currentNode}>
我们的this就是组件的实例对象,相当于在实例上添加了一个input1就是当前元素的节点
这样我们直接this.input1.value就可以获取到了
第三种:createRef
我们通过React.createRef()方法相当于在实例上创建了一个可以存储被ref识别的节点的容器
myref = React.createRef();
<input ref={this.myref}/> 相当于使用ref把当前元素存放在myref容器里
console.log(this.myref.current.value);
myref 是一个对象{current:input}然后通过current就可以获取到我们存储的节点
但是一个容器只能放一个元素,如果还想放其他的 myref2 = React.createRef();需在再来一个容器
受控组件和非受控组件
1、受控组件的状态由React组件的state来控制。在受控组件中,表单元素(如输入框、选择框等)的值通过受控组件的状态进行同步
2、非受控组件的状态不由React组件的state控制。在非受控组件中,表单元素的值由用户的交互直接更新,而不会通过React组件的状态进行同步,如使用ref
大部分时候使用受控组件来处理表单数据和状态
什么是高阶函数
参数是函数或者返回值是函数、满足其中一个就是
什么是函数珂里化?
函数的珂里化:通过函数调用继续返回调用函数的方式,实现多次接收参数最后统一处理的函数编码形式。
通过函数科利华,上面的代码就可以简写
请输入账号: <input type="text" onChange={this.saveData('name')}></input>
请输入密码: <input type="password" onChange={this.saveData('psw')}></input>
saveData = (params) => {
return (event) => {
this.setState({
[params]:event.target.value
})
}
}
不使用珂里化
请输入账号: <input type="text" onChange={(event) => this.saveData('name',event)}></input>
请输入密码: <input type="password" onChange={(event) => this.saveData('psw',event)}></input>
saveData = (params,event) => {
this.setState({
[params]:event.target.value
})
}
什么是脚手架?
创建一个基于xx库的模板项目。包含了所有的配置相关依赖,并且可以运行的简单页面。
使用脚手架开发的项目特点:模块化,组件化,工程化
第一步: 全局安装 npm i -g create-react-app
第二步: 切换到准备创建项目的目录,使用命令:create-react-app hello-react
第三步: 进入项目文件夹:cd hello-react
第四步: 启动项目:npm start / yarn start
react脚手架文件解释
public——静态资源文件夹
favicon.icon——网站页签图标
index.html——主页面
manifest.json——应用加壳的配置文件
robots.txt——爬虫协议文件
src——源码文件夹
App.css——App组件的样式
App.js——App组件
App.test.js——用于给App做测试
index.css——样式
index.js——入口文件
logo.svg——logo图
reportWebVitals.js 页面新歌能分析文件
解决运行报错问题
出现的问题:
问题1、项目启动报错。。。for each 解决办法
找到node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js这个文件,找到报错的代码,直接注释导致报错的那一行:
// RefreshRuntime.injectIntoGlobalHook(safeThis);
浏览器有缓存,可以新建一个无痕窗口查看
问题2、项目提示 大概就是说不要用ReactDOM.render,版本17的语法 了下面是原来的写法:
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
应该这么写:
import ReactDOM from 'react-dom/client'
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
组件化编码流程
1.拆分组件:拆分界面,抽取组件
2.实现组件的静态页面效果
3.动态显示初始化数据,数据名称,类型,显示在哪个组件
4.从绑定监听事件开始实现用户的交互
怎么把自己的项目放到github上管理
首先登陆github账号配置SSH 后,新建一个仓库
会给出提示:
git init 初始化
git branch -M main 这个是修改本地分支名称的指令
git status
git add
git commit -m "first commit"
git remote add origin https://github.com/xulifg/my-vue.git
git push -u origin main 推到远程分支上就修改成功了
为什么加- u?
相当于git push origin master 和 git branch --set-upstream master origin/master
介绍一个兄弟组件通信的库
Install via npm (npm install pubsub-js)
import PubSub from 'pubsub-js'
// 数据的依赖方订阅消息
componentDidMount() {
this.token = PubSub.subscribe('MY TOPIC',(msg,data)=>{
console.log(msg,data);
});
}
// 数据的改变方发生消息
PubSub.publish('MY TOPIC', 'hello world!');
// 关闭订阅
componentWillUnmount() {
PubSub.unsubscribe(this.token);
}
react生命周期
可以将生命周期分为俩个阶段—> render阶段执行和commit阶段执行。
或者用组件的四种状态将其划分,即Mount首屏状态渲染时、Update更新时、Unmount卸载时和Error子孙节点发生错误时。
图中标红的三个生命周期函数,在React17中已经被废弃了,不建议大家使用。
而替代它们的,就是这俩个标绿的函数。在React16.3时引入。
注意:在一个组件中,不要同时使用标红和标绿的函数,React会报错。
constructor() 初始化实例、对事件处理函数绑定实例
static getDrivedStateFromProps(props, state) 会在每次组件被重新渲染前被调用
render() 创建虚拟dom,更新dom
componentDidMount() 挂载组件后立即调用。
shouldComponentUpdate() 仅作为性能优化的方式存在,返回true执行render,反之不执行
getSnapshotBeforeUpdate 更新时在渲染到Dom之前被调用
生命周期执行过程
第一部分:初始渲染。
初始渲染时,调用ReactDOM.render。React的组件会形成一棵组件树。
进入render阶段。在render阶段,会执行 constructor、getDerivedStateFromProps/componentWillMount、render这三个函数。
采用深度优先遍历创建fiber树(即虚拟dom树)。从根节点开始创建。
进入Commit阶段。会先将整棵fiber树对应的DOM渲染到视图中,当渲染完成后,然后从子节点开始执行对应的生命周期函数componentDidMount。
第二部分:重复渲染
当用户执行会触发React重新渲染的操作时。
进入render阶段。
采用深度优先遍历创建fiber树。(每次重新渲染都会创建一棵虚拟DOM树,然后使用diff算法进行比较,如果该节点无变化,则不会触发其生命周期函数。有变化则来到第4步。)
reconcile算法标记变化。执行对应的函数shouldComponentUpdate和render
进入Commit阶段。会先将整棵fiber树对应的DOM渲染到视图中,当渲染完成后,然后从子节点开始执行对应的生命周期函数componentDidMount。
执行4中变化对应的视图操作。被reconcile标记变化了的节点会执行getSnapshotBeforeUpdate和componentDidUpdate。
最后,新创建的fiber树会替换掉之前的DOM树,结束。
react-router 5 的基本使用
router 路由器 route路由
react中router对象分为三种,第一种web 第二种 native 第三种 anywhere
我们web学习第一种即可,借助yarn add react-router-dom 库
link api 用来定义路由跳转连接
route 用来注册路由规则
这两个标签要包裹在一个router对象中
<BrowserRouter>
<Link to='/home'>首页</Link>
<Route path='/home' component={Home}></Route>
</BrowserRouter>
ReactDOM.createRoot(document.getElementById('root')).render(<BrowserRouter><App /></BrowserRouter>)
web对应的api是BrowserRouter
但是一个应用只能由一个路由对象管理,如果我们想要管理很多个组件怎么办?
直接把这个对象包裹在index.js中app组件的外层,这样整个项目都是使用一个router对象管理
一般组件和路由组件的区别
一、写法不同
一般组件:<Demo/>
路由组件:<Route path='/demo' component={Demo} />
二、存放位置不同(规范的)
一般组件:components
路由组件:pages
三、接收到的 props 不同
一般组件:传递什么值,接收到什么值
路由组件:接收到三个固定的属性(history、location、match)
switch
一般来说一个route 路径渲染一个组件,一一对应。如果同一个路径下面匹配了很多组件,会导致效率很低
所以需要还有switch 标签来包裹route路径
<Switch>
<Route exact path='/home' component={Home}></Route>
<Route path='/person' component={Person}></Route>
<Redirect to='/home'></Redirect>
</Switch>
模糊匹配、精准匹配
什么是模糊匹配,什么是精准匹配
模糊匹配就是我们传入的path 比规定路径中的path 要多,但是按照顺序符合路径,name就可以匹配
比如:home/a/b 路径:home 也可以正常展示的 默认就是模糊匹配
怎么开启精准匹配?
在route标签中加exact
什么时候开启严格匹配?
一般不会随便开,只有模糊匹配产生了问题才会开启严格匹配
Redirect重定向
我们打开页面没有点击之前,无法加载页面,可以使用
<Redirect to='/home'></Redirect>
这个应该写在route的最后面,最为一个兜底的人,是to 不是path
一定要注意路径前面没有. 同时必须有/
path = '/home'
嵌套路由
我们定义路由规则和引入组件都在router中进行操作,通过配置children 属性
注意children里面的path不需要加/
配置好了之后去对应的组件写navLink 这里的to不需要加/
news
message
那这个规则在哪渲染呢?我们在APP组件里使用的是{element}
在嵌套路由中,我们引入Outlet 定义路由出口。
import {Navigate} from 'react-router-dom'
import Home from '../pages/Home'
import About from '../pages/About'
import Message from '../pages/Message'
import News from '../pages/News'
let router = [
{
path:'/home',
element:<Home/>},
{
path:'/about',
element:<About/>,
children:[
{
path:'message',
element:<Message/>},
{
path:'news',
element:<News/>}
]
},
{
path:'/',
element:<Navigate to='/home'/>
}
];
export default router;
路由传参的三种方式:
有时候我们需要在点击link的时候,传递一些参数到我们点击展示的组件,有三种方式
第一种 params 传参
第一步:在link的url中写入需要传入的参数
<NavLink to={`/person/profile/message/${item.id}/${item.title}`}>{item.title}</NavLink>
第二步:在route中注册接收参数
<Route path='/person/profile/message/:id/:title' component={Message}></Route>
第三步:在对应的组件中通过this.props.match.params 方法拿到参数并使用
第二种 search传参
第一步:在link的url中写入需要传入的参数
<NavLink to={`/person/profile/message/?id=${item.id}&title=${item.title}`}>{item.title}</NavLink>
第二步:在route中注册接收参数
不需要接受注册
第三步:在对应的组件中通过this.props.location.search 方法拿到参数是
?key=value$key=value 的urlencoded编码的数据。
需要通过yarn add query-string 库来转换数据格式
import queryString from 'query-string';
qs.stringify(obj) 对象转化成urlencoded
qs.parse(str)urlencoded转化成对象
第三种 路由state传参
第一步:在link的url中写入需要传入的参数
<NavLink to={{pathname:'/person/profile/message',state:{id:item.id,title:item.title}}}>{item.title}</NavLink>
第二步:在route中注册接收参数
不需要接受注册
第三步:在对应的组件中通过this.props.location.state 方法拿到参数
注意点:刷新页面浏览器有缓存不会丢失state,但是清除缓存之后会丢失
编程式导航
就是不适用link我们使用函数去实现路由的跳转
1、showme = (id,title)=>{
this.props.history.push(`/person/profile/message/${id}/${title}`)
}
2、在route中注册接收参数
<Route path='/person/profile/message/:id/:title' component={Message}></Route>
3、在对应的组件中通过this.props.match.params 方法拿到参数并使用
基本上就第一步 和link 不一样
补充的两个方法:
1、this.props.history.goBack()
2、this.props.history.goForward()
3、this.props.history.go(-1)
自动路由跳转和withRouter
怎么实现没有点自动切换路由呢?
componentDidMount() {
setTimeout (()=>{
this.props.history.push(`/person/profile/message/${id}/${title}`)
},2000)
}
如果我们想在header组件里使用前景后退的API行不行?
不行,因为这个API只有路由组件才能用,但是header不是路由组件
解决办法?
在一般组件中引入
import {withRouter} from 'react-router-dom'
暴露方式改为:
export default withRouter(Header)
BrowserRouter 和 HashRouter的区别
1、底层原理不同
第一个使用的是h5的history API ,不兼容低版本浏览器,HashRouter使用的是URL的哈希值。
2、path的表现形式不同
第一个没有#,第二个localhost:3000/#/demo
3、刷新后对路由state参数的影响
第一个不会影响,因为保存在了history对象中;第二个会导致参数丢失
react-router 6 的变化
react-router 以三个不同的包发布到npm上,分别是
1.react-router 路由核心库,提供了 很对组件钩子
2.react-router-dom 包含react-router的所有内容,并添加一些专门用于dom的组件
3.react-router-native 包含router所有内容,并专门添加一些专门用于原生的api
与5相比有什么变化?
1.6成为默认版本
2.官方明确推出使用函数式组件,并新增了很多钩子
3.内置组件变化,例如移除了<Switch
变化1:路由重定向
原来的:
<Redirect to='/home' ></Redirect>
现在的:
<Route path='/' element = {<Navigate to='/footer'/>}></Route>
变化2:语法变化:component = {About } 改为 elelemnt= { }
<Routes>
<Route path='/header' element = {<Header/>}></Route>
<Route path='/list' element = {<List/>}></Route>
<Route path='/footer' element = {<Footer/>}></Route>
</Routes>
变化3:没有之前的类名了,现在className接受一个函数,这个函数接收一个isActive参数,当高亮的时候是true,还需要给返回值
原来的:
<NavLink activeClassName="demo" to='/home'>首页</NavLink>
现在的:
<NavLink to='/header' className={({isActive})=> {return isActive? 'active':'header'}}>
<Button type="primary">首页</Button>
</NavLink>
每一个都要去判断?封装一个函数
fucntion computedClassName ({isActive}) {
renturn isActive?'active':'header'
}
变化4: 原来的Switch包裹废弃,变成 Routes 而且这个必须和Route 标签一起使用
原来的
<Switch>
<Route exact path='/home' component={Home}></Route>
<Route path='/person' component={Person}></Route>
<Redirect to='/home'></Redirect>
</Switch>
现在的
<Routes>
<Route caseSensitive path='/home' element={<Home/>}></Route>
// caseSensitive 属性设置对路径的大小写敏感
<Route path='/about' element={<About/>}></Route>
<Route path='/' element={<Navigate to='/home'/>}></Route>
</Routes>
如何使用路由表管理
首先引入useRoutes 一定要加s
然后const element = useRoutes([
{path:'/home',element:<Home/>}
{path:'/about',element:<About/>}
])
变化5:路由传参
第一种 params
传递:
<li key={item.id} >
<NavLink to={`person/${item.id}/${item.title}`} >{item.content}</NavLink>
</li>
在路由表中注册一下,path 不需要``
{
path:'news',
element:<News/>,
children:[
{
path:'person/:id/:title',
element:<Person/>
}
]
}
然后在person组件里接收
const {id,title} = useParams();
return (
<div>
大家好,我是{id}好选手,
发言:{title}
</div>
第二种 search 传参
这里person和?直接没有/
<NavLink to={`person?id=${item.id}&title=${item.title}`} >{item.content}</NavLink>
在路由表中不需要要注册接受
直接在person组件中使用
import {useSearchParams} from 'react-router-dom'
export default function Person() {
const [search,setSearch] = useSearchParams();
const id = search.get('id');
const title = search.get('title')
第三种 state传参
<div>
<ul>
{
params.map((item)=>{
return(
<li key={item.id} >
<NavLink
to='person'
state={{
id:item.id,
title:item.title
}}
>{item.content}</NavLink>
</li>
)
})
}
</ul>
<Outlet></Outlet> 嵌套路由一定要使用outlet
</div>
不需要注册
在person组件中接收:
const {state:{id,title}} = useLocation();
编程式路由导航
onst navigate = useNavigate();
function tohome () {
navigate('/home'); 如果是params和search直接路径中传递参数
navigate(1);
navigate(-1);
一定要注意路径中/相当于覆盖当前,不加/ 相当于在后面拼接
navigate('url',{
replace:false,
state:{
id:item.id
}
})
}