# React

# 1. React相关介绍

# 1. React特点

# A. 声明式设计

react是面向数据编程,不需要直接去控制dom,你只要把数据操作好,react自己会去帮你操作dom,可以节省很多操作dom的代码。这就是声明式开发。

# B. JSX语法

JSX 是 JavaScript 语法的扩展。React 开发大部分使用 JSX 语法(在JSX中可以将HTML于JS混写)。

# C. 灵活

react所控制的dom就是id为root的dom,页面上的其他dom元素你页可以使用jq等其他框架 。可以和其他库并存。

# D. 使用虚拟DOM、高效

虚拟DOM其实本质就是一个JavaScript对象,当数据和状态发生了变化,都会被自动高效的同步到虚拟DOM中,最后再将仅变化的部分同步到DOM中(不需要整个DOM树重新渲染)

# E. 组件化开发

通过 React 构建组件,使得代码更加容易得到复用和维护,能够很好的应用在大项目的开发中。

# F. 单向数据流

react是单向数据流,父组件传递给子组件的数据,子组件能够使用,但是不能直接通过this.props修改。 这样让数据清晰代码容易维护。

# 2. 环境搭建

# A . 全局安装脚手架(不推荐)

npm install create-react-app -g

# B. 通过npx搭建项目(官方推荐)

npx create-react-app 项目名
# 关于create-react-app

create-react-app 是FaceBook的React团队官方出的一个构建React单页面应用的脚手架工具,它本身集成了 webpack ,并配置了一系列内置的 loader 和默认的npm脚本,可以很轻松的实现零配置就可以快速开发React的应用

# 关于npx

在 npm 的5.2.0版本开始,自动安装了npx

npx是什么? npx会帮助你执行依赖包里的二进制文件

npx会自动查找当前依赖包中的可执行文件,如果找不到,就会去PATH里找。如果依然找不到,就会帮你安装

该命令建议运行在node的12.13.0版本的基础上

# C. 清除项目中的默认文件

删除掉新项目中 src/ 文件夹下的所有文件

# 1.进入到src目录下
cd 项目名/src

# 2.删除src目录下的所有文件
# 如果你使用 Mac 或 Linux:
rm -f *
# 如果你使用 Windows:
del *

# 3.新建一个index.js文件
touch index.js

# 4.然后回到项目文件夹
cd ..

# 5.复制一下代码到index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from "./App"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);

# 6.运行项目
npm start

# D. 书写第一个组件

import React from 'react'

class App extends React.Component{
  render(){
    return (
    	<div>我的第一个组件</div>
    )
  }
}

export default App

# E. VSCode中JSX的编写优化

# 2. 组件化开发

# 定义组件

定义组件分为3步:

  1. 导入React核心模块

  2. 定义组件类

  3. 导出组件

在src目录下新建App.js文件:

//1、导入React核心模块
import React from 'react'

//2、定义组件类
class Hello extends React.Component{   //类
    render(){     //函数
        return (   //返回值
            <div>
                hello world !!! 我是组件
            </div>
        )
    }
}

//3、导出组件
export default Hello

/*
	为什么继承Component?
		因为继承Component,组件里就可以写render,return(标签),然后React就会帮助渲染成浏览器认识的标签
*/

# 引入组件

在需要引入该组件的index.js中,导入,就可以直接使用这个组件了:

//import 组件名 from '文件路径'

//1、导入Hello组件 (首字母必须大写)
import Hello from './App' 

ReactDOM.render(
// 2、使用Hello组件 (首字母必须大写) 
<Hello /> 
, document.getElementById('root'));

//注意:Hello是组件名,在使用的时候就应该写JSX标签写法,而不能直接写Hello

# 注意:

  1. 定义组件的时候,return 后面只能有一个根标签,不能有多个,但这个标签内部可以有其他多个标签

  2. 使用组件的时候,首字母必须大写,(是为了和标签进行区分,标签是小写)

  3. 如果最外层实在不想放置一层div根目录,可以使用 <></> 空标签代替

  4. 写jsx要套在 return () 里,写js语法要套在 {}

# 3. jsx语法糖

React使用JSX来替代常规的javascript。jsx是一个看起来很像XML的JavaScript语法扩展,在React中会被babel编译为JavaScript。

语法糖:一个功能,有两种完成方式,其中简单的写法。叫语法糖

Babel 是一个 JavaScript 编译器

# a. JSX的特点

1. jsx执行更快,因为它在编译为JavaScript代码后进行了优化
2. 它是类型安全的,在编译过程中就能发现错误
3. 使用jsx编写模版更加简单快速

# b. JSX几个注意的格式

  1. React的JSX是使用大写和小写字母来区分本地组件和HTML标签
  2. JSX和HTML的标签属性的区别
HTML标签属性 JSX 原因
for htmlFor for在js中为for循环的关键字
class className class在js中为声明类关键字
style 需使用JS对象(使用双花括号--{{}} )

# c. jsx 和 html 区别

  1. 行内样式 必须是一个对象 第一个{}代表js环境 第二个 {} 代表 对象格式
<div style="{{width:"200px"}}"></div>
  1. jsx中不要使用class,用className代替

  2. 在jsx中使用js代码,必须要写在{}

  3. jsx 本地图片先引入 后使用

  4. 其他的,都可以当做HTML语法来用

# d. 文件引入方式

//引入后立即执行
import "./Index.css"

//什么时候调用什么时候执行
import Img from "../static/logo.png"

# e. JSX是React虚拟出来的DOM对象

// js创建DOM元素
document.createElement("div")

// React的标签对象
React.createElement("div",{className:"box"},"hello")

# 4. 类式组件

import {Component} from 'react'

export default class App extends Component{
  // constructor 专门用来初始化
  constructor(props){   
    super(props)
    // 定义组件内部数据
    this.state = {
      num:20
    }
  }
  render(){
    return (
      {/* 在JSX上获取组件内部数据 需要通过 this.state.变量名 */}
    	<div>{this.state.num}</div>
      <button onClick={this.handleClick.bind(this)}>按钮</button>
    )
  }
  handleClick(){
    // 需要修改到组件内部数据,需要用到this.setState方法来修改
    // 在函数中,如果需要使用this,就得在调用的时候传递this
    // this.setState() 这个方法是异步的
    // this.setState() 提供的第二个参数是一个回调函数,修改了数据之后才执行
    this.setState({
      num:this.state.num+1
    },()=>{
      // 修改数据之后才执行
      console.log(this.state.num)
    })
  }
}
# super的作用究竟是什么?

super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

# super()加与不加props的区别究竟在哪里呢?

这是因为 react 在初始化 class 后,会将 props 自动设置到 this 中,所以在任何地方都可以直接访问 this.props,除了一个地方:constructor ;所以如果你需要在构造函数内使用this.props,就需要传递props作为super()的参数。

# a. 插值语法

import React, { Component } from "react";

export default class App3 extends Component {
  state = {
    name: "苏东旭",
    num: 10,
  };
  render() {
    return (
      <div>
        <p>{this.state.name}</p>
        <p>{this.state.num}</p>
      </div>
    );
  }
}

# b. 事件的三种写法

this.事件名.bind(this,传递的参数)

import {Component} from 'react'

export default class App extends Component{
  constructor(props){
    super(props)
    this.state = {
      title:"我是标题"
    }
    this.handleClick = this.handleClick.bind(this)
  }
  render(){
    return (
    	<>
      	<button onClick = {this.handleClick.bind(this)}>按钮1</button>
      	<button onClick = {this.handleClick}>按钮2</button>
      	<button onClick = {()=>this.handleClick()}>按钮3</button>
      </>
    )
  }
  handleClick(){
    this.setState({
      title:"修改后的标题"
    })
  }
}

# c. 双向数据绑定

react不会问react双向绑定原理的,没有双向绑定

import React, { Component } from "react";

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      val: "默认值",
    };
  }
  inp(e) {
    this.setState({
      val: e.target.value,
    });
  }
  render() {
    return (
      <div>
        <input
          type="text"
          value={this.state.val}
          onChange={this.inp.bind(this)}
        />
        <p>{this.state.val}</p>
      </div>
    );
  }
}

# d. 循环

react只支持map遍历

import {Component} from 'react'

export default class App extends Component{
  constructor(props){
    super(props)
    this.state = {
      arr:['html','css','js','jq','node','ts','vue','react']
    }
  }
  render(){
    return (
    	<>
      	<ul>
      		{
          	this.state.arr.map((item,index)=>{
              return (
                <li key={index}>{item}</li>
              )
            })
        	}
      	</ul>
      </>
    )
  }
}

# e. 数组操作

  1. 普通写法
import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      arr: ["html", "css", "js", "jq", "vue"],
    };
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>添加</button>
        <ul>
          {this.state.arr.map((item, index) => {
            return <li key={item}>{item}</li>;
          })}
        </ul>
      </div>
    );
  }
  handleClick() {
    this.setState({
      // 浅拷贝
      arr: [...this.state.arr, "react"],
    });
  }
}
  1. 深拷贝写法
import React from "react";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      arr: ["html", "css", "js", "jq", "vue"],
    };
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>添加</button>
        <ul>
          {this.state.arr.map((item, index) => {
            return <li key={item}>{item}</li>;
          })}
        </ul>
      </div>
    );
  }
  handleClick() {
    // 深拷贝
    let newArr = JSON.parse(JSON.stringify(this.state.arr));
    newArr.push("react");
    this.setState({
      arr: newArr,
    });
  }
}

# f. 父子传值

# 1. 父传子

在父组件的子组件标签中设置自定义属性,并将要传递的数据作为其属性值

在子组件中直接通过 this.props.自定义属性 获取父组件传递的数据

# 父组件传值
  1. 在父组件中引入子组件

    // 组件名首字母一定大写
    import 子组件名 from "子组件位置"
    
  2. 直接用就行,无需注册

    render(){
    	return(
    		<div>
    			<子组件 自定义属性={父组件数据}></子组件>
    		</div>
    	)
    }
    
# 子组件接值
<p>{this.props.自定义属性名}</p>
  1. 子组件中限制默认值

    static defaultProps = {
      自定义属性名:"属性值",
      title:"默认值"
    }
    
  2. 子组件中限制类型

    // 引入限制类型的模块
    import PropTypes from "prop-types"
    
    // 限制类型 注意不能直接写类型,需要单独引入 限制类型 的模块
    static propTypes = {
      自定义属性名:PropTypes.String
    }
    

# 2. 子传父

# 子组件传值

在子组件中为某元素添加点击事件,并将事件触发的方法进行声明,在方法内通过 this.props.自定义事件(传递数据)

在父组件的子组件标签中使用该自定义事件,不加on,自定义事件触发的方法在父组件中进行声明,方法的形参就是子组件传递过来的数据

  1. 需要一个契机,为元素添加点击事件

    <button onClick={this.子组件方法.bind(this)}>子组件按钮</button>
    
  2. 声明点击事件的方法,并通过 this.props.自定义事件(传参)

    子组件方法(v){
      this.props.自定义事件("传递的数据")
    }
    
# 父组件接值
  1. 子组件标签内,使用自定事件,不加on

    <子组件 自定义事件={this.父组件方法.bind(this)}></子组件>
    
  2. 父组件中声明子组件自定义事件触发的方法

    父组件方法(v){
      //形参v就是子组件传递的数据
    }
    

# g. 组件跨级值传递Context

React组件之间的通信是基于props的数据传递,数据需要一级一级从上到下传递。如果组件级别过多传递就会过于麻烦。React中 Context 配置可以解决组件跨级值通信

适合获取数据,如果修改的话,还是建议放在redux中

# 方式一

# 向下传递
import React,{Component} from 'react'
import PropTypes from 'prop-types'
// 爷爷
export default class Comp1 extends Component{
  // 声明要传递的数据类型
  static childContextTypes = {
    fnum:PropTypes.number
  }
  // 保存要传递的数据到上下文环境中
  getChildContext(){
    return {
      fnum:40
    }
  }
  render(){
    return (
    	<Child></Child>
    )
  }
}
// 爸爸
class Child extends Component {
  render(){
    return (
    	<div>
      	<ChildChild></ChildChild>
      </div>
    )
  }
}
// 孙子
class ChildChild extends Component {
  // 在哪个组件中想要获取fnum这个数据,就必须写两个东西
  // 1. 接收的类型
  static contextTypes = {
    fnum:PropTypes.number
  }
  render(){
    return (
    	<div>
      	孙子组件
        {/* 2. 通过this.context.fnum获取值 */}
        {this.context.fnum}
      </div>
    )
  }
}

# 方式二

配置createContext

// ctx.js 哪个组件使用就引入
import {createContext} from "react"
const ctx = createContext()
export default ctx

/*
ctx有两个组件(标签)
	Provider	发送数据
	Consumer	接收数据
*/
# 向下传递

父辈通过Provider的value属性向下传递数据

后代通过 (value)=>{} 接收数据

import React, { Component } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
  render() {
    return (
      <Provider value={{ name: "苏东旭" }}>
        <Child></Child>
      </Provider>
    );
  }
}
// 爸爸
class Child extends Component {
  render() {
    return <ChildChild></ChildChild>;
  }
}
// 孙子
class ChildChild extends Component {
  render() {
    return (
      <Consumer>
        {(value) => {
          return <h2>{value.name}</h2>;
        }}
      </Consumer>
    );
  }
}

# 向上传递

父辈传参时传一个函数,并声明一下该函数,函数的形参就是将来后代传递过来的数据

后代在函数的形参处传值

import React, { Component } from "react";
import ctx from "../utils/ctx";
let { Provider, Consumer } = ctx;
// 爷爷
export default class App extends Component {
  render() {
    return (
      <Provider value={{ name: "苏东旭", fn: this.data.bind(this) }}>
        <Child></Child>
      </Provider>
    );
  }
  data(v) {
    console.log(v);
  }
}
// 爸爸
class Child extends Component {
  render() {
    return <ChildChild></ChildChild>;
  }
}
// 孙子
class ChildChild extends Component {
  render() {
    return (
      <Consumer>
        {(value) => {
          return (
            <div>
              <h2>{value.name}</h2>
              <button onClick={value.fn("孙子向上传递的数据")}>传递</button>
            </div>
          );
        }}
      </Consumer>
    );
  }
}

# h. 组件的生命周期

类的生命周期分为三个大阶段:挂载、更新、卸载

每个大阶段又有若干小阶段,其中在整个生命周期中render会被执行两次(挂载和更新阶段各执行一次)

# 挂载阶段

# constructor : 当对象刚刚类创建出来的时候
# componentWillMount : 组件即将渲染【没用,现在已经废弃了】
# render : 组件正在渲染
# componentDidMount : 组件渲染完毕
// 当对象刚刚类创建出来的时候
constructor(){
  super()
  console.log("生命周期的第一个阶段---刚刚创建出来")
  //作用:就是为了初始化state的数据
}

// 组件即将渲染【没用,现在已经废弃了】
UNSAFE_componentWillMount(){
  console.log("生命周期的第二个阶段---组件即将渲染")
}

// 组件正在渲染
render(){
  console.log("生命周期的第三个阶段---组件正在渲染")
}

// 组件渲染完毕
componentDidMount(){
  // react官方要求,推荐在componentDidMount中请求数据
  console.log("生命周期的第四个阶段---组件渲染完毕")
}

# 更新阶段

# shouldComponentUpdate : 应该更新么,返回true或false
# componentWillUpdate : 即将更新【已废弃】
# render : 正在更新
# componentDidUpdate : 更新完毕
# state更新
import React, { Component } from "react";

export default class Child extends Component {
  constructor() {
    super();
    this.state = {
      num: 1,
    };
  }
  dian() {
    this.setState({
      num: "苏东旭",
    });
  }
	// 在这个方法中,判断数据修改前后是否一致,不一致才去render,减少不必要的更新,优化更新性能
  shouldComponentUpdate(nextProps, nextState) {
    console.log("修改的第一阶段:可以修改么");
    if (this.state.num === nextState.num) {
      return false;
    } else {
      return true;
    }
  }

  UNSAFE_componentWillUpdate() {
    console.log("修改的第二阶段:即将修改【已废弃】");
  }

  render() {
    console.log("修改的第三阶段:正在修改");
    return (
      <div>
        Child
        <p>{this.state.num}</p>
        <button onClick={this.dian.bind(this)}>按钮</button>
      </div>
    );
  }
  componentDidUpdate() {
    console.log("修改的第四阶段:修改完毕");
  }
}

# props改变
componentWillReceiveProps(){
  // props数据的变化,才会触发这个方法的执行
}

# 卸载阶段

# componentWillUnmount : 主要用于释放数据、清空缓存
componentWillUnmount() {
  // 释放数据 清空缓存
  console.log("被销毁了");
}
# 总结:
# componentDidMount 适合做数据请求
# shouldComponentUpdate 优化更新性能

# 5. 函数式组件

react里面组件分两种

  • 类式组件

  • 函数式组件

    • 没有state,但是提供了很多的hook函数,数据渲染简洁
    • 没有this,它指向window
    • 没有生命周期函数(靠 hook 模拟出来)
    • 写的都是js原生,数据不是响应式的
// 这就是一个简单的函数式组件
import React from 'react'

export default function App() {
  return (
    <div>Demo</div>
  )
}

# useState 响应式数据

# 使用:

let [变量名,修改变量的回调] = useState(默认值)

# 修改:

修改变量的回调(变量名)

import React,{useState} from "react"

export default function App() {
  // 第一个数据 就是我们想要使用的组件内部数据
  // 第二个数据 是专门用来修改第一个数据的方法名	setNum(新值) 表示把第一个数据改成新值
  // 第三个数据 useState方法的形参就是第一个数据的初始值
  const [num,setNum] = useState(0)
  function hdClick(){
    setNum(num + 1)
  }
  return (
    <div>
    	<p>{num}</p>
      <button onClick={hdClick}>按钮1</button>
      <button onClick={() => setNum(num + 1)}>按钮2</button>
    </div>
  )
}

# 父子组件传值

# 父传子

  1. 给儿子自定义属性

  2. 儿子在函数参数位置接取props

import React,{useState} from 'react'

function Child(props){
  let {num} = props
  return (
  	<div>
    	<h2>{num}</h2>
    </div>
  )
  
}

export default function Father(){
  const [num,setNum] = useState(10)
  return (
  	<div>
    	<Child num={num}></Child>
    </div>
  )
}

# 子传父

  1. 给儿子传函数

  2. 儿子调用函数传值

import React, { useState } from "react";

function Child(props) {
  let { num, changeNum } = props;
  return (
    <div>
      <h2>{num}</h2>
      <button onClick={changeNum}>按钮</button>
    </div>
  );
}

export default function Father() {
  const [num, setNum] = useState(10);
  return (
    <div>
      <Child num={num} changeNum={() => setNum(num + 1)}></Child>
    </div>
  );
}

# Hook 多级组件传值

ctx.js

import {createContext} from "react"
const ctx = createContext()

export default ctx

父辈组件

import React from "react";
import Baba from "./Baba";
import ctx from "./ctx";
let { Provider } = ctx;
export default function Yeye() {
  const jie = (v) => {
    console.log(v);
  };
  return (
    <Provider value={{ name: "苏东旭", fn: jie }}>
      <div>
        yeye
        <hr />
        <Baba />
      </div>
    </Provider>
  );
}

中间

import React from "react";
import Son from "./Son";
export default function Baba() {
  return (
    <div>
      Baba
      <hr />
      <Son></Son>
      <Sunzi />
    </div>
  );
}

后代组件

import React from "react";
import { useContext } from "react";
import ctx from "./ctx";

export default function Son() {
  const value = useContext(ctx);
  return (
    <div>
      Son
      <p>{value.name}</p>
      <button
        onClick={() => {
          value.fn("苏东旭");
        }}
      >
        契机
      </button>
    </div>
  );
}

# Hook模拟生命周期

componentDidMount 请求数据 组件渲染完毕

componentDidUpdate 数据更新完毕

componentWillUnmount 页面关闭的时候

useEffect(回调函数,数组)

  1. 第二个参数是空数组 [] ,不监听任何一个数据的变化 代替 componentDidMount
  2. 第二个参数不写,监听所有内容,代替componentDidUpdate
  3. 第二个参数 非空数组[有内容] 只监听 [] 里面的数据的改变 类似watch,不代替任何一个生命周期
  4. 如果里面有return 函数,代表页面关闭的时候执行 代替componentWillUnmount

useEffect做请求数据,一定是空数组

里面不支持async/await

# Hook获取DOM元素

useRef 获取DOM元素

import React from "react";
import { useRef } from "react";

export default function App6() {
  const inp = useRef();
  const box = useRef();

  const dian = () => {
    console.log(inp.current.value);
    console.log(box.current);
  };

  return (
    <div>
      App6
      <input type="text" ref={inp} />
      <div ref={box}>盒子</div>
      <button onClick={dian}>获取dom</button>
    </div>
  );
}

# Hook 计算属性

useMemo(回调函数,[监听的内容])

import React from "react";
import { useMemo } from "react";
import { useState } from "react";

export default function App7() {
  const [num, setNum] = useState(10);
  let total = useMemo(() => {
    return num * 2;
  }, [num]);
  return (
    <div>
      <p>{num}</p>
      <p>{total}</p>
      <button
        onClick={() => {
          setNum(num + 1);
        }}
      >
        按钮
      </button>
    </div>
  );
}

# 6. 路由

# 路由切换原理

<html lang="en">
  <head>
    <title>路由切换原理</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
  </head>
  <body>
    <ul>
      <li><a href="#/login">点击跳转登录页</a></li>
      <li><a href="#/reg">点击跳转注册页</a></li>
    </ul>
    <div id="routerview"></div>
    <script>
      // 路由表
      let routes = {
        "#/login":"./login.html",
        "#/reg":"./reg.html"
      }
      // 当路由发生变化时 hashchange事件,重新加载 routes中的视图
      window.addEventListener("hashchange",()=>{
        $("#routerview").load(routes[location.hash])
      })
    </script>
  </body>
</html>

# 安装路由

npm install react-router-dom@6
  • 在 src/router/index.jsx
// 先安装路由 npm i react-router-dom@6
// 这不仅仅是一个路由文件,它也是一个路由组件
// BrowserRouter是一个路由组件(自带的history模式),同时还有一个HashRouter(自带hash模式)
// 引入三个路由组件
import { BrowserRouter, Routes, Route } from "react-router-dom";

// BrowserRouter 指定路由模式 HashRouter 两种路由模式
// Routes 路由表
// Route 路由

// 1. 引入要跳转的组件

import Home from "../views/router/Home";
import User from "../views/router/User";

// 2. 创建路由
const router = (
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<Home />}></Route>
      <Route path="/user" element={<User />}></Route>
    </Routes>
  </BrowserRouter>
);

export default router;

# 子路由

# 配置子路由

Route嵌套Route

<Route>
	<Route></Route>
</Route>

# 子路由页面展示

import {Outlet} from 'react-router-dom';

<Outlet></Outlet>

# 路由跳转

# Link方式

import {Link} from "react-router-dom";

<Link to="/路径">标题</link>

# JS方式

import {useNavagate} from "react-router-dom"

let navigate = useNavigate()

const goHome=()=>{
  navigate("/Home")
}

<button onClick={goHome}>首页</button>

# 路由传参

# 1. 动态路由

优点:美观,但是需要修改路由配置文件

# 传参
  • 配置文件
<Route path="/路由规则/:id/:name/xxxxx"></Route>
  • 路由传参
// Link方式
<Link to="/路由规则/参数1/参数2/...">首页</Link>

// JS方式
import {useNavagate} from "react-router-dom"
let navigate = useNavigate()

const goHome=()=>{
  navigate("/路由规则/参数1/参数2/...")
}

<button onClick={goHome}>首页</button>
# 接参

Hook

import (useParams) from "react-router-dom"

let params = useParams()
console.log(params)

# 2. 通过查询字符串

# 传参
//?id=19&name=苏东旭
// Link方式
<Link to="/路由规则?参数1=xxx&参数2=xxx...">首页</Link>

// JS方式
import {useNavagate} from "react-router-dom"
let navigate = useNavigate()

const goHome=()=>{
  navigate("/路由规则?参数1=xxx&参数2=xxx...")
}

<button onClick={goHome}>首页</button>
# 接参

Hook

import {useSearchParams} from "react-router-dom"

const [data] = useSearchParams()
console.log(data.get('参数1'))

# 3. 通过navigate函数传参

# 传参

添加第二个参数 {state:{}}

import {useNavigate} from "react-router-dom"
let navigate = useNavigate()

const goHome=()=>{
  navigate("/路由规则",{
    state:{
      id:17,
    	name:"小星星"
    }
  })
}

<button onClick={goHome}>首页</button>
# 接参
import (useLocation) from "react-router-dom"

let location = useLocation()
console.log(location.state)

总结

传参 useNavigate

接参 useLocation

# 7. Redux状态管理

# 安装

npm i redux react-redux

# 使用redux

redux只有两种属性

  • 数据(自定义起名:baseState)
  • 修改(自定义起名:reducer)

# 定义

import {createStore} from "redux"

// 初始值
const baseState = {
  const:10,
  name:"张三"
}

// 设置数据和修改  state初始数据 action修改方法
const reducer = (state=baseState,action)=>{
  // 必须先深拷贝
  let nstate = JSON.parse(JSON.stringify(state))
  //============================
  	【把修改的方法写这里】
    console.log(action)
  	if(action.type === 'type值'){
      //业务逻辑
    }else if(action.type === 'type值'){
      //业务逻辑
    }
  //============================
  return nstate
}


// 创建仓库
const store = createStore(reducer)
// 开放出去
export default store

# 传值

//引入仓库
import store from "../../store"
//引入发送数据的组件
import {Provider} from "react-redux";


//希望哪些后代能共用 redux的值就可以使用Provider进行包裹
<Provider store={store}>

</Provider>

# 接取

import {useSelector} from 'react-redux'

const data = useSelector(state=>state)
console.log(data.键)

# 修改

import {useDispatch} from 'react-redux';

const dispatch = useDispatch()
const fn = () =>{
  // dispatch() 可以直接调用 store/index.js的reducer方法
  dispatch({
    type:"",  //必须有type,其他的随意
    //数据直接发给reducer的action
  })
}

<button onClick={fn}></button>

总结

传值 Provider

接值 useSelector

修改 useDispatch