React

124 阅读17分钟

React精记

1-redner注意事项

1- 挂载的位置(react容器)同一个页面可以指定多个

2- render可以调用多次,最后一次呈现的内容,会将之前的覆盖掉

3- 挂载的位置,不要被指定多次(会Warning)

4- 不要将body或html作为react容器(会Warning)

5- render呈现的内容,如果是字符串,字符串使用html标签,不会被浏览器识别

6- 可以使用连缀写法

2-jsx的基本语法

强烈建议:如果写入的JSX有嵌套,建议使用()将其包裹, root.render(<div/>),若一个则建议不要
强烈建议:将文件的名字以jsx结尾。如果将元素常量放置到外部,
                                         
注意1:在使用JSX时,标签必须要闭合 如:<a/> 
注意2:在使用JSX时,标签的名字首字母不允许大写(react中大写默认以组件渲染)                           注意3:在使用JSX时,不允许出现HTML没有内置标签(浏览器不支持的标签,不允许出现)
注意4:传入的JSX有且只能是一个根元素
注意5:如果有显示多个兄弟元素,可以在外围增加一个div
注意6:可以使用React提供的包裹组件,来解决一个根元素的问题
//eact.Fragment只是起到了一个包裹的作用,不会转为真实dom 可以加key属性
<></>也是一个包裹标签,是React.Fragment的语法糖。
​
//jsx本身也是表达式 ,所以她可以出现在{}里,{<a></a>}//你可以在 if 语句和 for 循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX   
    * {}写入的内容只支持表达式,不支持JS语法。
    * js语句:不支持
    *   if 条件语句
    *   for 循环语句
    *   switch 选择语句
    * js表达式:一个表达式会对应一个结果,表达式其实是一种特殊的JS语句
    *   三元表达式
    *   变量
    *   常量
    *   fn()
                                   

3-元素渲染

React 只更新它需要更新的部分,并只会进行必要的更新来使 DOM 达到预期的状态。
1-条件渲染
  root.render((
            <div>{sex===1?"男":"女"}|{bol?"真":"假"}</div>
            <div>  {bol && "今天天气不错"}  </div>
        ))
​
2-属性渲染
#数数组作为属性进行展示时是有逗号的,直接渲染是不带逗号,对象不能被展开
  <p className={arr}></p>==》 <p class=“a,b”> 加了两个类名
​
3-样式渲染
style的属性值必须要设置为对象
            <div style={{
                width:"100px",
                height:"200px",
                background:"red"
            }}></div>
​
4-列表渲染
一般通过map 或定义[].push
//返回JSX:箭头函数使用(),可以指定返回的值。
​

4-this问题

1:原生中为什么行内添加事件,回调函数中的this不指向事件源了

答:行内增加事件,是将字符串赋值过去,虽然带括号但是不会执行,当点击的时候会以js代码执行该函数,并且没有传任何参数,并且他会从window下面开始找 ,原本的this就丢失了什么都没有,后面要输出this还是看其如何调用(react默认严格模式,ES6类语法也是,箭头函数不自带this

2:类组件中解决this指向undefined方式

    1- 将函数直接设置为箭头函数
    优点:方便
    缺点:不能复用,如果逻辑代码较多,阅读不方便,传递参数不方便
​
    2- 可以将箭头函数在类中进行定义
    优点:可以被复用,代码多时也易于阅读
    缺点:函数在实例中定义,如果组件被多次使用,会占用内存。
    
    3-建议:可以通过bind将this进行指定(绑定)
    优点:传递参数方便,可以复用
    缺点:每次调用都要写bind,(自己添加)但是每次渲染都会执行 bind 方法生成一个新的函数(额外开销),并导致     子组件进行重新渲染
    
     4-在实例属性中进行绑定
     缺点:组件被多次使用,每次使用均会在内存中创建实例属性clickHandler
          传递参数只能够进行一次指定,动态 指定参数不方便
     优点:当你在使用函数时,不需要再次写bind
    
    
​

5-类组件

5.1-props与state相关

#属性不允许直接修改,若迫不得已。可拿到属性值然后改掉
//class组件又称为复杂组件  有状态组件
props:
父子组件传参通过属性:<Child username="xx" age={this.props.age} ></Child>
子组件需要接收:this.props.username
    //属性是可以进行类型的限制的。
    1- 引入prop-types.js,可以通过该文件对组件接收的属性进行类型限制
    2- 为类组件增加静态属性 static propTypes(限制类型),static defaultProps(可以设置默认值)
                                                             
state:状态可以修改,状态通过setState是 《异步修改》
                                                      
       方式一:this.props.setState({name:"wang"})  //参数是一个对象
       方式二:this.props.setState({name:"wang"},()=>{// 当数据更新完毕且界面渲染完成之后执行该回调。})       
       
       方式三:this.props.setState((prevState,props)=>){
                               return {name:"xx"}
                               },()=>{//状态修改后执行该回调})
//在react@17的版本下  promise和定时器里 setStates是同步的
                                                                      

5.2-生命周期

生命周期指的是类组件。类组件从创建到销毁的过程称其为该组件的生命周期。

在组件的生命周期中,所暴露出来(在阶段中所自动执行)的函数称为钩子函数。

生命周期旧

生命周期旧

20200702114631693

5.1.1- 挂载阶段

#在组件挂载阶段暴露出来的钩子函数,除 render以外,均只运行一次。
 实例化constructor=》在挂载之前UNSAFE_componentWillMount=》指定要挂载的内容render=> 挂载结束之后componentDidMount
····················
若父子组件的情况:
 实例化constructor=》在挂载之前UNSAFE_componentWillMount=》指定要挂载的内容render=> 子组件执行上面步骤=>挂载结束之后(子组件)componentDidMount=》父组件componentDidMount

5.1.2- 更新属性阶段

 UNSAFE_componentWillReceiveProps(nextProps){}//属性发生更新的时候 执行
 shouldComponentUpdate(nextProps){做逻辑判断是否更新} // 当要更新属性时,执行到该钩子,this.prop  还未更新。接收的形参nextProps是即将要更新的属性
 UNSAFE_componentWillUpdate(nextProps){} 
 render(){//到这里 属性已经更新}
 componentDidUpdate(prevProps){prevProps为上一次的属性}   
​

5.1.3- 更新状态阶段

  shouldComponentUpdate(nextProps, nextState){}
  UNSAFE_componentWillUpdate(nextProps, nextState){}
  render(){   this.state.num = 100; //不会触发钩子而且render也不会 可强制更新
              this.forceUpDate() }
  componentDidUpdate(prevProps, prevState){}
​

5.1.4- 卸载阶段

componentWillUnmount(){}
root.unmount()

5.2- 生命周期新

生命周期新

<script type="text/babel">
    const root = ReactDOM.createRoot(document.querySelector("#root"));
    class App extends React.Component {
        state = {
            userName: "zhangsan"
        }
        render() {
            return (
                <div>
                    <button onClick={() => {
                        this.setState({
                            userName: this.state.userName + "!"
                        })
                    }}>点我</button>
                    <Child userName={this.state.userName}></Child>
                </div>
            )
        }
    }
    class Child extends React.Component {
        state = {
            a: 1,
            b: 2,
            userName: "lisi"
        }
        // 作用:可以将接收到属性与当前的数据状态进行合并。
        // 在什么时候执行:
        //     1- 组件挂载时会运行。
        //     2- 父组件执行render后会执行。
        //     3- 在当前组件中执行this.setState
        //     4- 强制更新
        // 特点:
        //     1- 组件中必须定义state
        //     2- 必须要有返回值,且返回值必须是对象或null
        //     3- 如果返回的对象中的属性与当前状态的属性冲突,那么会将数据状态进行覆盖
        //     4- getDerivedStateFromProps是一个静态方法,该方法的this是undefined
        static getDerivedStateFromProps(props) {
            console.log(props, this);
            return {
                // a:100,
                c: 3,
                d: 4,
                ...props //返回的是this.state
            }
        }
        render() {
            // console.log(this.state);
            return (
                <div>
                    <h3>Child</h3>
                    <button onClick={() => {
                        // this.forceUpdate();// 强制更新
                        this.setState({
                            a: this.state.a + 1
                        })
                    }}>{this.state.a} </button>
                </div>
            )
        }
        // 注意:
        // 1- getSnapshotBeforeUpdate需要与componentDidUpdate结合使用
        // 2- getSnapshotBeforeUpdate它的返回值,会作为componentDidUpdate的第三个参数
        // 3- 执行该钩子时,状态值已经发生变化
        // 4- 当前的DOM还未更新。
        // 在此处可以生成日志信息。
        getSnapshotBeforeUpdate(prevProps, prevState) {
            // prevState:状态更新之前的值
            // this.state:当前状态值
            console.log(prevState.a, this.state.a);// 执行该钩子时,状态值已经发生变化
         console.log(document.querySelectorAll("button")[1].innerText)//当前的DOM还未更新。
            return 100;
        }
        componentDidUpdate(prevProps, prevState, snapshot) {
            console.log("更新完毕!componentDidUpdate", snapshot)
            console.log(document.querySelectorAll("button")[1].innerText)////当前的DOM已更新。
        }
    }
    root.render((
        <App></App>
    ))
​
</script>
/*
使用getDerivedStateFromProps(nextProps, prevState)的原因:
旧的React中componentWillReceiveProps方法是用来判断前后两个 props 是否相同,如果不同,则将新的 props 更新到相应的 state 上去。在这个过程中我们实际上是可以访问到当前props的,这样我们可能会对this.props做一些奇奇怪怪的操作,很可能会破坏 state 数据的单一数据源,导致组件状态变得不可预测。
​
而在 getDerivedStateFromProps 中禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去访问this.props并做其他一些让组件自身状态变得更加不可预测的事情。
​
使用getSnapshotBeforeUpdate(prevProps, prevState)的原因:
在 React 开启异步渲染模式后,在执行函数时读到的 DOM 元素状态并不总是渲染时相同,这就导致在 componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。
​
而getSnapshotBeforeUpdate 会在 render 之后被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与componentDidUpdate 中一致的。
*/
​
​

6-ref 获取react元素

1- ref与字符串结合使用  <h3 ref={"title"}>App</h3>  , this.refs.title==>h3    (官方不推荐了)
   ref与组件结合使用时,可以获得组件实例。this.refs.子组件 ,从而可以实现组件之间的通讯。但是并不是传递属性,不会在子组件里通过this.props拿到
​
2-ref与箭头函数结合使用 
    React元素的属性ref的值如果是一个箭头函数,那么不可以通过this.refs获取其真实DOM
    ref的值是箭头函数的特点:
    1- 当组件在挂载时,箭头函数会执行。
    2- 箭头函数接收的参数即是真实的DOM.
    3- 在使用时,需要将接收到的DOM作为当前实例的属性。
    <h3 ref={ele => this.title = ele}>App</h3>
3-ref与React.createRef结合使用 (#推荐)
    ref使用方式三:React.createRef  title = createRef(); <h3 ref={this.title}>App</h3>
    1- 自定义一个实例属性,其值为React.createRef()
    2- 为React元素增加ref属性,其值设置为自定义的实例属性。
    3- 可以通过实例属性.current得到真实DOM
​

7-受控组件和非受控组件

受控组件:如果在表单元素中使用value,checked那么会受其值的控制。
         一旦组件受控,需要结合onChnage事件来更改value值  
         对于表单的两种操作:1- 设置表单值,2-收集表单数据,更改数据状态
非受控组件:defaultValue,defaultChecked
​

8-函数组件(重点重点重点重点)

函数组件是无状态组件 简单组件 没有生命周期钩子

8.1-props属性相关

#传递属性
1:
<Child userName={"zhangsan"} age={12}></Child> //传递属性
function Child(props) {//通过形参props对象接收属性}
    
2:
<BookList bookInfo={boyBook}>
    <h3 style={{color:"blue"}}>男生必读</h3>//传递
</BookList>
{ props.children }//放在props下的children里了
    
#函数组件限制类型
函数可以直接增加属性。称为函数的静态属性
Child.propsTypes={} ,Child.defaultTypes={}

8.2-Hook

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。* 只能在函数组件和自定义hook中使用*

1-useState函数组件中的state 状态

设置状态

1- useState是React模块提供的一个方法
2- useState返回的是一个数组,接收的参数即是初始状态值。
3- 返回的数组有两个元素,第一个元素即是状态,第二个元素是修改状态的方法。
4- 当通过setXXX修改状态之后,函数会重新执行,注意:再次执行时,状态的值为上一次的结果(useState拥有记忆性)
5- 修改状态的方法规范:以set开头,后续加上状态名,使用驼峰命名法
例:const [num, setNum] = React.useState(1);   setNum(num - 1)//异步设置
#注意: 传入的参数要保证与修改的状态的引用地址不同。否则界面不会更新

2-useCallback

缓存内联回调函数

useCallback:可以将函数进行缓存处理。
useCallback函数,接收的第一个参数是内联回调函数,第二个参数是依赖性数组
如果使用了useCallback,第二个参数建议声明,如果不声明相当于useCallback无用的方法。
1-如果省略第二个参数,不会有记忆。
2-如果只是写[],代表着该函数会进行记忆(缓存)
3-如果写的[num],代表着num发生变化,不会设置num缓存(保证num是最新的状态)。

3-useMemo

缓存值

useCallback记忆的是函数,useMemo记忆的结果(将接收函数执行以后的结果进行返回)
useMemo第二个参数是数组。
1-如果将第二个参数省略,那么不会产生记忆。
2-如果将第二个参数设置为空数组,那么所得到值不会发生变化。
3-如果将第二个参数设置为[num],只有状态num发生变化,才会重新调用指定的函数,得到新的结果。
#传入useMemo的函数会在渲染期间就执行,所以不要写不在渲染期间执行的代码,如useEffect里的代码

4-useRef

获取dom

1- 引入useRef  const btn = React.useRef("sdasdas"); //不写参数就是undefined
2- 将useRef函数运行的结果赋值给常量。// inputRef = useRef();
3- 将生成的常量作为操作的React元素的ref属性值 //<input ref={inputRef} type="text" />
4- 在使用时,可以通过常量名.current可以得到真实的DOM。
//useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内持续存在。useRef 会在每次渲染时返回同一个 ref 对象。

5-useContext(会以redux代替)

useContext可以帮助我们解决跨组件传递数据,实现数据的共享。(类组件也可用)

//context文件下的index.js
import {createContext} from "react"; 
export default createContext(0); 
//App.jsx里引入
import globalContext from "./context";
​
* 1-要通过React.createContext方法生成一个数据(对象)
*     1-1 createContext需要在src下创建一个目录context,在context中新建文件index.js进行执行。
*     1-2 createContext是一个函数,接收的数据是共享状态的初始值,返回的是一个对象
*     1-3 对象当中拥有Provider(提供者),Consumer(消费者),//可以看作一个组件
​
* 2-如果需要在Child组件中使用数据。
*   简单 :
    child组件中 直接用创建时候设置的初始值
*   import globalContext from "../context";
*   <p>child:{result}</p>
    
*   设置到数据的传递:
*   App.jsx:
*           const [num,setNum] = useState(100);
*           <globalContext.Provider value={{name,setName}}>//传多个值用对象
                <Child userName={userName}/>
            </globalContext.Provider>
    接收:
        import globalContext from "../context";
        const {num,setNum} = useContext(globalContext);
        <p>child:{num}</p> //并没有通过属性传参 所以props里没有的
······························································
        <div>
            <globalContext.Provider value={{ num, setNum }}>
                <Child userName={userName} />
            </globalContext.Provider>
        </div>

6-useReducer(会以redux替代)

是useState的替代方案

useReducer也被称为状态管理器。通过useReducer可以对自身的状态进行集中式管理。

如果 state 逻辑较复杂且包含多个子值等等

reducer的使用流程:
1- 创建一个函数,该函数可以称为reducer函数,作用:可以对数据(数据状态)进行操作
2- 该函数可以接收两个参数,第一个参数是状态,第二个参数是荷载的内容.
3- 需要通过useReducer,可以获得状态以及修改状态的方法
4- useReducer接收两个参数:1-reducer函数 2- 初始状态
5- dispatch 执行时,需要传递一个对象。
/*
prevState是要更改的状态,action的值为dispatch函数传递的数据(action对象)
返回的值是最新的状态.
action对象需要设置type属性,通过type属性可以得知要对数据进行怎样的操作.*/
const reducer = function (prevState, action) {
    const state = { ...prevState };//改引用地址
    // 将状态更改为{num:100} 
    if (action.type === "jia") {
        state.num += action.payload;
    }
    if (action.type === "jian") {
        if (state.num > 1)
            state.num -= 1;
    }
    return state;
}
function App(props) {
    console.log(useReducer());// [undefined,f]
    console.log(useReducer(reducer, {
        num: 1
    }));// [ {num: 1},f]
    const [state, dispatch] = useReducer(reducer, { num: 0 });
    return (
        <div>
            <button onClick={() => {
                dispatch({
                    type: "jian"
                });
            }}>-</button>
            {state.num}
            <button onClick={() => {
                dispatch({
                    type: "jia",
                    payload: 2
                });
            }}>+</button>
        </div>
    );
}

7-useEffect

1- useEffect可以接收一个函数(相当于componentDidMount-挂载阶段,componentDidUpdate-更新阶段)
    useEffect(() => {
        console.log(document.querySelector("button").innerText, "Effect"); //初次执行也是在render结束后,若状态改变即更新依然是render结束后
    })
​
2- useEffect第二个参数是一个数组, (更新阶段)
        2-1如果你省略该数组,当任何状态更新都会执行第一个参数(回调函数)
        2-2如果第二个参数设置为一个空数组,那么回调函数只会在挂载完毕之后执行一次,更新阶段不会执行。(componentDidMount)
        2-3如果数据内指定了状态,那么回调函数只会在指定的状态发生变化时和挂载结束时执行。componentDidMount componentDidUpdate
       useEffect同组件里可以多次使用
       
//默认情况下,effect 会在每轮组件渲染完成后执行。这样的话,一旦 effect 的依赖发生变化,它就会被重新创建。       
// 可以返回一个函数,该函数会在组件销毁前执行 类似componentWillUnMount      

8-useLayoutEffect

    useEffect(()=>{
        console.log("useEffect",num)
        const pre = Date.now();// 获取当前时间
        // 延迟0.5秒
        while(Date.now()-pre<500){}//0.5秒内一直循环
        if(num === 0)
            setNum(Math.random());
    },[num])
​
    // useLayoutEffect会阻塞浏览器的渲染。
    useLayoutEffect(()=>{
        console.log("useLayoutEffect",num)
        const pre = Date.now();// 获取当前时间
        // 延迟0.5秒
        while(Date.now()-pre<500){}
        if(num === 0)
            setNum(Math.random());
    },[num])
#其余一样 可查官网

图片引入相关(create-react-app)

1- 如果图片来自于其它服务,直接写完整地址 <img src="https://static.zoncvea56.jpeg" alt="" />
2- 如果图片来自于本项目,那么可以通过import引入图片 import vue from "./assets/img/vue.png";
3- 如果图片来自于本项目,那么也可以通过require const vue2 = require("./assets/img/vue.png");    

样式引入相关(create-react-app)

import "./App.css" //根据组件名 直接引用 (若都用直接引入 如果属性重名 父会覆盖子组件的样式)
import styles from "./App.module.css";  //模块化引用,样式文件的名字需要以.module.css结尾
<p className={styles.cl}>app</p>

9-路由(重点)

一个路由就是一个映射关系(key:value) key为路由路径, value可能是function/component

路由两种模式:historyRouter hashRouter

下载:cnpm install react-router-dom

路由切换:从A路由切换至B路由,可以称其为一次路由切换。切换伴随者路由销毁和挂载
从A路由切换至B路由:首先会将A路由进行销毁,然后再将B路由进行挂载。反之亦然
#一级路由的 path 的名字前面要加斜杠,但二级路由推荐不用加斜杠,避免不必要的报错。
​
<Route path={"/"} element={<h3>主页</h3>}>asd </Route> //也可以直接写表达式(包括jsx)
 <Route path={"/"} element={<Home />}>asd </Route> //默认只会找一次从上到下
 <Route path={"*"} element={<Home />}> </Route> //所以path都不匹配 才触发
 {/*当请求地址为/home,那么会重定向到path为/的路由中*/} 重定向
  <Route path={"/home"} element={<Navigate to={"/"} />}></Route>
​
//路由导航
import {
    Routes,//路由组件
    Route,//直接包裹路由组件
    NavLink,//导航组件 会在浏览器里转换为a标签
    Navigate,// 跳转组件  重定向
​
} from 'react-router-dom'    
​
会将路由导航抽离到components中,<NavLink to={"/"}>首页</NavLink> 
NavLink:自带的样式 类是.active,点谁谁有这个类名
​
自定义样式2中方式:
className可写字符串类名,也可以写箭头函数
箭头函数: 1:该箭头函数会在界面挂载完之后执行。接收一个参数(类型是对象{isActive:true})
         2:isActive:当浏览器的地址与当前NavLink的to属性相同,那么为true,否则为false
​
​
//路由切换伴随路由销毁和挂载,写在useEffect()里
//1: /#/newsList,2:/newList
BrowserRouter为history路由模式: 在打完包之后放置在生产环境以后需要单独对其进行配置。
2种路由设置模式:import { HashRouter/BrowserRouter as Router } from 'react-router-dom'
​
//路由嵌套
/*使用路由嵌套的流程:
    1- 要在一级路由(Routes组件直接包裹的路由称为一级路由)内包裹上其它的路由(二级路由,子路由)
    2- 二级路由访问的地址: 首选要访问到一级路由的path,然后才可以访问到二级路由的path
       比如: /my/car  ==>my是一级路由的地址标识   car是二级路由的地址标识。
    3- 二级路由指定的element元素需要在一级路由element元素上进行呈现 。
       ####一级路由呈现二级路由的内容需要通过引入Outlet组件进行挂载位置 。
*/
​
#将二级路由设置为默认选中的三种方式(一级路由为my)
<Route path={""} element={<MyCollections/>}></Route>//相当于/my/“”
<Route path={"/my"} element={<MyCollections/>}></Route>// /my的时候就显示collection,无高亮
<Route index element={<MyCollections/>}></Route>
    
#设置二级路由地址的2方式:
1-地址相对于 /my
 <Route path={"mycart"} element={<MyCart />}></Route>
2-地址相对于于站点根目录
  <Route path={"/my/mycart"} element={<MyCart />}></Route> 
      
 #路由重定向的2种方法
 1:
 import {Navigate,// 跳转组件} from "react-router-dom"
<Route path={"/home"} element={<Navigate to={"/"}/>}></Route>
 2:定义组件Redirect 通过传参的形式     
  <Route path={"/home"} element={<Redirect to={"/"} />}></Route>
  引入useNavigate ==》const navigate = useNavigate()=》useEffect =》 navigate(to)
​
#路由传递参数(重点)
#1:search传递参数
//1- 刷新数据不会丢失。因为数据是在地址中(查询字符串)的 2- 不方便传递引用类型。
                {/* 字符串 */}
                <NavLink to={"/one/?a=1&b=2"}>search01</NavLink>
                {/*对象*/}
                <NavLink to={{
                    pathname: "/one/?a=10&b=2" //认为你的地址是/one/?a=10&b=2 认为/one是
                                  //pathname 进行比较就不相等 单纯传递参数都行导航的化第一或第三
                }}>search02</NavLink>
                {/*通过search属性指定数据*/}
                <NavLink to={{
                    pathname: "/one",
                    search: "a=100&b=300"
                }}>search03</NavLink>
​
                 # <按钮实现需要引入useNavigate,并组件中调用>
                 字符串形式 直接拼接,对象形式直接写或者分开写
                {/*通过按钮来实现1*/}
                <button onClick={() => {
                    navigate("/one?a=90&b=91")
                }}>search04</button>
                {/*通过按钮来实现2*/}
                <button onClick={() => {
                    navigate({
                        pathname: "/one?a=8&b=9"
                    })
                }}>search05</button>
                 {/*通过按钮来实现3*/}
                <button onClick={() => {
                    navigate({
                        pathname: "/one",
                        search: "?a=88&b=9"
                    })
                }}>search06</button>
1:search接收参数
#引入useLocation后的值没法直接用,所以要转换
1.1-引入useLocation=》组件中调用返回的是对象,并且search是字符串//search: "?a=88&b=9"
所以可用封装函数 将字符串变为对象 然后对象里拿值
1.2-通过下载querystring接收参数 然后去除问号 调用parse方法转为对象
1.3-可以通useSearchParams来接收数据。引入后调用,返回数组[{},f],取出searchParams这个对象,并用其get方法searchParams.get("a")获取值
​
#2-state传递参数
特点:数据没有放置在地址中,可以方便的传递引用类型。放置在state中,刷新数据不会丢失,如果重新打开一个进程数据丢失。
//通过事件 并且要用到useNavigate(“path”,{})
 <button onClick={() => { navigate("/two",{state:{}})}>state2</button>
2-接收参数:useLocation.state //解构state对象时,为了放置state为空可用||{},或者设置默认值
​
#3- params传递参数(最多)
传参:
 {/*<NavLink to={"/three/1/2"}>params</NavLink>*/}
{/*<NavLink to={"/three/1-2"}>params</NavLink>*/}
<NavLink to={"/three/1-2.html"}>params</NavLink>//.html伪类型 随便写,-/也可以改
​
{/*<Route path={"/three/:id/:type"} element={<Three/>}></Route>*/}
{/*<Route path={"/three/:id-:type"} element={<Three/>}></Route>*/}
<Route path={"/three/:id-:type.html"} element={<Three/>}></Route>
接收参数:
引入useParams=》{id: '1', type: '2'}  

\