尚硅谷react学习笔记

什么是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
        }
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值