react快速入门(对比vue)

发布于:2024-04-28 ⋅ 阅读:(20) ⋅ 点赞:(0)

自从react官方推出16.8版本出现hook以来,面向对象编程逐渐被函数式编程取代,所以本文章将全部以函数式编程,来讲解react的相关知识 最近要入职了公司用的react,不得不提前了解一下react,这里面东西可能不全,但是我后续慢慢学到会继续慢慢更新,大佬勿喷,对学完vue刚开始学react的小伙伴可能会有帮助

请结合我的另一篇vue基础知识对比学习

react基础语法

在聊hooks之前,我们先来学习一下react组件式开发的基本操作 JSX

一个简单的例子
import React from 'react';

function tset(props) {
    return (
        <div className="container">  //注意jsx必须只有一个跟标签 当然如果你不需要可以写成《》《/》这样的形式
  <h1>Hello, World!</h1>
</div>
    );
}

export default tset;
这就是一个简单的jsx模板 映入眼帘的很显然是return返回的标签。在react中,我们书写html都需要放到这个return语句中,实际上,整个jsx底层调用的是React.createElement,上面的代码其实就相当于
React.createElement("div", { className: "container" },
React.createElement("h1", null, "Hello, World!")
很显然,这样的写法显得十分麻烦,于是推出了jsx来做React.createElement语法糖。在jsx return里面,你可以几乎使用完全的html书写习惯,但是注意只是几乎,特别的,在html标签中class将不在使用而转为className,要始终记得,在return语句中,你书写的不是html,而是类似与js书写的标签,class转换为className,使用-连接的属性要变成大写
了解简单的html书写之后,我看一下样式如何添加上去
 以上面的container为例,我们无法直接在jsx里面书写类似这样子
   .container{
               width:100%;
               height:100%;
               }   
如果需要上样式的话,我们有两种常用的手段
1 我们使用<div style={container}> 使用内敛样式的形式,虽然jsx我们无法直接书写css代码,但是我们可以通过变量的形式保存css字符串,然后当作内联样式嵌入html
 例如这样
const container= {
    width: "100px",
    height: "100px",
    background: "red",
  };  //注意用逗号哦,类似于对象的写法,时刻谨记,jsx中书写的是类似于css或者html的js
第二种办法
  我们将css抽离出来,单独形成css文件,随后引入达到样式的书写
   import "./css/App.css";,
  这样我们直接写<div className="container"> 使用className的形式上样式即可
 .container {
    width: "100px";
    height: "100px";
    background: "red";
} 
 

接下来我们了解一下在jsx中,如何使用类似于v-for 和v-if进行渲染

在vue里面,我们很容易就写出 这样的形式,之后vue就会帮我们循环渲染到模板中,但是在react却一样
<ul>
    <li v-for="item in 20" :key="item.id"></li>
</ul>
 以下面例子为例
 let arr=    [
      { id: "01", content: "js", age: 13 },
      { id: "02", content: "html", age: 15 },
      { id: "03", content: "css", age: 20 },
    ],
假设我们需要以ul li的形式渲染到页面上,我们肯定无法直接写成这样,没有对应的指令让我们这样书写
<ul>
    <li ???="item in arr" :key="item.id"></li>
</ul>
 正确的做法应该是
 const show=arr.map((e)=>{
     return (
         <ul key={e.id}>  //注意,身为父元素的ul必须加上唯一的id,否则控制台会报错
             <li>{e.content}{e.age}</li>           
         </ul>
     )
 })
 然后在jsx中,这样就可以实现循环渲染
 function tset(props) {
    return (
		<div className="container">
 			 {show}
		</div>
    	);
}
我们不妨打印一下看看返回的是什么东西,不难看出,返回的结果个数组,数组里面是经过react.element构建来的

1714268493519.png

了解上述之后,我们应该不难想出,条件渲染是如何的
 let show2 = show.length > 5 ? show2 : null;我们重新定义一个变量,来进行判断,当然这里我只采用了简单的三目,写成函数返回也是可以的
 之后我们要展示的就不是show了而是show2
 <div className="container">
 			 {show2}
		</div>

hook与事件

HookReact 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

Hooks 的出现,首先能解决如下的一些问题:

  • 告别令人疑惑的生命周期
  • 告别类组件中烦人的 this
    • 在类组件中,会存在 this 的指向问题,例如在事件处理函数中,不能直接通过 this 获取组件实例,需要修改 this 指向
  • 告别繁重的类组件,回归前端程序员更加熟悉的函数

另外,Hooks 的出现,还有更加重要的一个信号,那就是整个 React 思想上面的转变,从“面向对象”的思想开始转为“函数式编程”的思想。这是编程范式上面的转变。

编程范式:

  • 命令式编程:告诉计算机怎么做(How),我们需要给计算机指明每一个步骤
    • 面向过程
    • 面向对象
  • 声明式编程:告诉计算机我要什么(What
    • 函数式编程
    • DSL(领域专用语言,HTML、CSS、SQL

声明式编程并不是新的产物,它是和命令式编程同期出现的。但是,早期更加流行命令式编程。不过随着近几年整个项目工程越来越复杂,以前的命令式编程就有点力不从心,所以现在慢慢开始流行声明式编程。

因此当你学习 Hooks 的时候,会发现突然多了一些以前不熟悉的概念,例如:纯函数、副作用、柯里化、高阶函数等概念。

当然,你可能好奇“面向对象”和“函数式编程”有什么区别,这里推荐一篇文章:

Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。
  • 你可以使用 useEffect 来模拟 componentDidMountcomponentDidUpdatecomponentWillUnmount
    • useEffect 的回调函数会在组件挂载(相当于 componentDidMount)和更新(相当于 componentDidUpdate)后执行。
    • 如果 useEffect 的回调函数返回了一个清理函数,该函数会在组件卸载(相当于 componentWillUnmount)时执行。

第一个hook

在react16.8以后中,hook的出现大大提高了开发的效率,在react中也存者类似于vue的响应式,虚拟dom,单项数据流等等
在这里我们只简单介绍两个hook,后续在做补充
1 useState   详细看官方文档 https://react.docschina.org/reference/react/useState
useState 是一个 React Hook,它允许你向组件添加一个 状态变量。
·为组件添加状态
·根据先前的 state 更新 state
·更新状态中的对象和数组
·避免重复创建初始状态
·使用 key 重置状态
·存储前一次渲染的信息
基本用法
import { useState } from 'react';  从react上引入  是不是有点类似于 import { ref } from 'vue'呢
而useState用法如下,useState传入你要定义的数据,然后会返回一个包括数据的变量和针对对应数据操作的方法函数
习惯上我们使用【age,setAge】这样的格式书写 age为你定义的数据28,setAge是针对当前数据进行操作的函数
  const [age, setAge] = useState(28);
  const [name, setName] = useState('Taylor');
  const [todos, setTodos] = useState(() => createTodos());
不妨看一下结构出来的两个是什么

1714269984294.png

可以看出,拿到的是简单的数据,还有一个复杂的函数,我们不必关系他到底什么是,我们只需要会使用即可
接下来,我们做一个简单的例子,在那之前,我们简单了解一下react绑定事件的方式
react的事件绑定并不像vue一样采用@语法糖,而是有些类似于原生html写事件一样(内敛)
原生html我们可以   <button onClick="hancleClick(e)">点我修改age </button>
在react中,写法也是类似
<button onClick={(e) => changeAge(e)}>点我修改age </button>
注意注意,不难这样写<button onClick={changeAge(e)}>点我修改age </button>  如果你想要传递参数的话,不可以这样写的,需要写成上述的形式。当然,如果你没有参数需要传递<button onClick={changeAge}>可以写成这样
ok,我们尝试一下
import React, { useState } from "react";
function Tset(props) {
  const [age, setAge] = useState(28);
  function changeAge(val) {
    setAge((e) => {
      return e + val;
    });
  }
  return (
    <div className="container">
      <h1>{age}</h1>
      <button onClick={() => changeAge(1)}>点我+1</button>
    </div>
  );
}
export default Tset;
在上述例子中,我需要指出的是
{age}就是类似于vue的{{age}},将数据展示到页面上
然后changeAge接收一个参数val(1),在里面使用setAge对age进行操作,注意,不能直接对age进行操作
类似于
 function changeAge(val) {
     再次注意,请不要对数据直接进行操作,如果需要操作数据请使用setAge方法,在里面进行操作
    age=age+val  //控制台报错 Assignment to constant variable.
     setAge((e)=>{
         //return e++   //不能直接对数据进行操作
          return e + 1; 可以写这样
     })
     如果你想将age变为一个固定的值,你也许可以这样
     setAge(1)  //这样的写法类似于 setAge(()=>1) 会将ag变为固定值
  }
整体来说
setAge的返回值会替换掉原来的Age的值,所以这就是为什么请不要对数据进行直接操作的原因
在这里我需要指出,在hook之前,我们使用this.state = {
      xxx : xxx  来进行赋值
    }
使用this.setState({
  xxx: 新值  进行修改
})
请注意,如果使用这样的写法,请永远记住,setSate是异步操作。

我们不妨打印一下看看这个setAge((e)=>{consle.log(e)})是什么东西
不难看到,数据已经变化了,但是打印出来的e却是上一个值
所以我们需要记住,setAge中传来的参数是上一个值,而非最新值

1714271314314.png

第二个Hook

副作用的概念

  • 纯函数:一个确切的参数在你的函数中运行后,一定能得到一个确切的值,例如下面的例子:
function test(x){
  return x * 2;
}

x => 2 ===> 4
x => 3 ===> 6
  • 如果一个函数中,存在副作用,那么我们就称该函数不是一个纯函数,所谓副作用,就是指函数的结果是不可控,不可预期。
  • 常见的副作用有发送网络请求、添加一些监听的注册和取消注册,手动修改 DOM,以前我们是将这些副作用写在生命周期钩子函数里面,现在就可以书写在 useEffect 这个 Hook 里面
第二个hook是useEffect,用来处理副作用
简单介绍一下useEffect,useEffect传入两个参数,第一个参数是要执行的函数,第二个参数是依赖项
怎么说呢
如果不传入第二个依赖项
useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    document.title = `你点击了${count}次`;
    console.log(`你点击了${count}次`);
  });
这样写的话,就类似于vue中的update生命周期,每当组件进行更新或者页面发生变化的时候就会调用一次

如果
useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    document.title = `你点击了${count}次`;
    console.log(`你点击了${count}次`);
  },[]);
传入一个空的依赖项,那么这个就只会执行一次,有没有类似于 vue mounted的生命周期呢,
所以这种情况就可以用来发请求获取数据,如果没有传入依赖项,那么就会不断进行发送请求死循环了

如果
useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    document.title = `你点击了${count}次`;
    console.log(`你点击了${count}次`);
  },[count]);
如果传入了对应的依赖项,那么就有点类似于 vue的watch(()=>??,()=>{},{imider...首次监视})了,根据依赖项的变化进行执行,如果依赖项变化了就执行函数。

import { useState, useEffect } from "react";
function App() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    document.title = `你点击了${count}次`;
    console.log(`你点击了${count}次`);
  });

  function clickhandle() {
    setCount(++count);
  }
  return (
    <div>
      <div>你点击了{count}次</div>
      <button onClick={clickhandle}>+1</button>
    </div>
  );
}

export default App;

另外,函数还可以有返回值,也是一个函数,用来处理函数产生的副作用,我们叫清理函数

看这样一种情况,在这里我们在副作用函数里写了一个计时器,我们很容易想到,不断的点击调用副作用函数,计时器也会发生高频触发的情况,显然这不是我们想要的

1714274640247.png

 import { useState, useEffect } from "react";
function App() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    console.log(`你点击了${count}次`);
    setInterval(() => {
      console.log("点击了");
    }, 1000);
  }, [count]);

  function clickhandle() {
    setCount(++count);
  }
  return (
    <div>
      <div>你点击了{count}次</div>
      <button onClick={clickhandle}>+1</button>
    </div>
  );
}

export default App;

想要解决这种情况

import { useState, useEffect } from "react";
function App() {
  let [count, setCount] = useState(0);

  useEffect(() => {
    // 书写你要执行的副作用,会在组件渲染完成后执行
    //   //初次渲染执行一次
    //   //如果希望副作用只执行一次,传入第二个参数为空数组为依赖数组
    console.log(`你点击了${count}次`);
    let time = setInterval(() => {
      console.log("点击了");
      console.log("副作用函数执行");
    }, 1000);
    return () => {
        ~~~~~~~~可以看到,这里副作用函数返回了一个新的函数,我们称之为清理函数,用来处理因为副作用函数产生的副作用的
      clearInterval(time);
      console.log("清理函数执行");
      //初次渲染不会执行
      //     //清理函数,清理函数会在渲染完成后,副作用函数执行前执行
    };
    //   //在这个数组中写入了谁依赖项,谁变化才会引起副作用函数与清理函数
    //   //如果想只执行一次的话,写入空数组即可,例如发起网路请求的时候
  }, [count]);

  function clickhandle() {
    setCount(++count);
  }
  return (
    <div>
      <div>你点击了{count}次</div>
      <button onClick={clickhandle}>+1</button>
    </div>
  );
}

export default App;

自定义hook

除了使用官方内置的 Hook,我们还可以自定义 Hook,自定义 Hook 的本质其实就是函数,但是和普通函数还是有一些区别,主要体现在以下两个点:

  • 自定义 Hook 能够调用诸如 useStateuseRef 等,普通函数则不能。由此可以通过内置的 Hooks 获得 Fiber 的访问方式,可以实现在组件级别存储数据的方案等。
  • 自定义 Hooks 需要以 use 开头,普通函数则没有这个限制。使用 use 开头并不是一个语法或者一个强制性的方案,更像是一个约定。

App.jsx

import { useState } from 'react';
import useMyBook from "./useMyBook"

function App() {

  const {bookName, setBookName} = useMyBook();
  const [value, setValue] = useState("");


  function changeHandle(e){
    setValue(e.target.value);
  }

  function clickHandle(){
    setBookName(value);
  }

  return (
    <div>
      <div>{bookName}</div>
      <input type="text" value={value} onChange={changeHandle}/>
      <button onClick={clickHandle}>确定</button>
    </div>
  )
  
}

export default App;

useMyBook

import { useState } from "react";

function useMyBook(){
    const [bookName, setBookName] = useState("React 学习");
    return {
        bookName, setBookName
    }
}

export default useMyBook;

生命周期

React Hooks 是 React 16.8 引入的新特性,它们允许你在不编写类组件的情况下使用状态和其他 React 特性。Hooks 并不直接提供传统类组件中的生命周期方法(如 componentDidMountcomponentDidUpdatecomponentWillUnmount 等),但你可以使用一些特定的 Hooks 来模拟这些生命周期行为。

以下是几个关键的 React Hooks,以及它们如何与生命周期方法相对应:

  1. useState:允许你在函数组件中添加状态。
  2. useEffect:这是一个强大的 Hook,可以用来模拟大部分生命周期方法的行为。它可以在组件渲染后执行副作用,并且在组件卸载时清理这些副作用。
  3. useLayoutEffect:与 useEffect 类似,但它会在所有的 DOM 变更之后同步执行副作用。如果你需要读取 DOM 布局并同步触发重渲染,使用它。
  4. useCallback:返回一个记忆化的回调函数,只有在依赖项改变时才会更新。
  5. useMemo:返回一个记忆化的值,只有在依赖项改变时才会重新计算。
  6. useRef:返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数,类似于类组件中的 createRef
  7. useImperativeHandle:用于自定义使用 ref 时公开给父组件的实例值。
  8. useContext:用于访问 React Context。

虽然这些 Hooks 不能一对一地映射到生命周期方法,但你可以使用它们来实现类似的功能。例如,你可以使用 useEffect 来模拟 componentDidMountcomponentDidUpdatecomponentWillUnmount

  • useEffect 的回调函数会在组件挂载(相当于 componentDidMount)和更新(相当于 componentDidUpdate)后执行。
  • 如果 useEffect 的回调函数返回了一个清理函数,该函数会在组件卸载(相当于 componentWillUnmount)时执行。

受控组件与非受控组件

​ 了解之后我们来了解一下受控组件与非受控组件

受控组件

无论是学习 Vue,还是 React,最重要的是要转换思想,这一步非常重要,往往也比较困难。

在以前 jQuery 时代,开发人员需要获取到 DOM 节点,然后进行操作。而在现代前端开发中,采用的是 MVVM 的模式,将视图和视图模型进行绑定,视图模型的改变,会自然的带来视图的改变。开发人员需要专注在视图模型上面。

因此,这里所谓的受控组件,本质上其实就是将表单中的控件和视图模型(状态)进行绑定,之后都是针对状态进行操作。

例子1

注意,在这里我=我们使用了inp标签,如果想要拿到inp标签的内容,我们仍然还是需要使用传统的dom.val进行拿到数据
import React, { useState } from "react";

function Tset(props) {
  let [state, setState] = useState(""); //使用useState进行数据定义
    注意,如果不对state值进行重新赋值的话,inp输入框里面是不会有你输入的东西的,这就是受控组件
  function handleChange(e) {  //inp的change方法
    setState(() => {
      return e.target.value;
    });
      如果全部注释掉的话,界面input输入框中无论你输入什么,都不会有任何显示,inp输入框的值收到state的显示,state有值,则输入框有值,state如果没有值,则输入框也没有值,且无法输入值
      因此,这里所谓的受控组件,本质上其实就是将表单中的控件和视图模型(状态)进行绑定,之后都是针对状态进行操作。
      // setState(() => {
     // return e.target.value;
    //});
  }
  function clickHandle() {
    // 提交整个表单
    console.log(`你要提交的内容为:${state}`);
  }
  return (
    <div>
      <input type="text"
          value={state} //绑定state
          onChange={(e) => handleChange(e)} />
      <button onClick={clickHandle}>提交</button>
    </div>
  );
}

export default Tset;

例子2对用户输入的内容进行限制

import React, { useState } from "react";
function Tset(props) {
  const [xiaoxie, setXs] = useState();
  const [shuzi, setSz] = useState();

  function changes(e) {
    let name = e.target.name; //判断是对第几个输入框进行输入
    switch (name) {
      case "one":
                   //根据不同的输入框执行不同的操作
        setXs(() => {
          return e.target.value.toUpperCase();  //将用书输入的小写转化为大写,并且覆盖掉原来的值
        });
        break;
      case "two":
            //根据不同的输入框执行不同的操作
        if (Number(e.target.value)) {
          setSz(e.target.value);
          break;
        } else {
          alert("请输入数字");
          setSz((e) => e);
          break;
        }
    }
  }

  return (
    <div>
      <input
        type="text"
        name="one"
        onChange={changes}
        value={xiaoxie}
        placeholder="请输入小写"
      ></input>
      <input
        type="text"
        name="two"
        onChange={changes}
        value={shuzi}
        placeholder="请输入数字"
      ></input>
    </div>
  );
}

export default Tset;

例子3下拉列表

这里要注意的是,针对下拉列表,与input同理,受控组件收到设置的值的约束,如果需要改变值需要使用setValue方法
当然你可以直接写道onChange里面,     onChange={(e) => setValue(e.target.value)}就像这样,直接将当前选择的值覆盖掉原来的
import React, { useState } from "react";
function Tset(props) {
  const [value, setValue] = useState("css");
  return (
    <div>
      <select
        onChange={(e) => setValue(e.target.value)}
        value={value}  //绑定value
        key="sss"
      >
        <option value="html">html</option>
        <option value="css">css</option>
        <option value="js">js</option>
      </select>
    </div>
  );
}

export default Tset;

例子4多选框

针对多选框
import React, { useState } from "react";
function Tset(props) {
  let [checks, setChecks] = useState([
    { content: "js", checked: true },
    { content: "html", checked: false },
    { content: "css", checked: true },
  ]);
  function handelChange(index) {
    setChecks((e) => {
       !!!! 再次注意,请不要直接对数据进行操作,如果有必要,请先将数据生成一份保存下来,如下
      const newChecks = [...e];
        随后针对新的数据进行操作,操作完之后在完全覆盖掉原来的数据
      newChecks[index].checked = !newChecks[index].checked;
      return newChecks;
    });
  }
  return (
    <div>
          //当然,如果你这样写不习惯,你也可以选择使用变量然后进行map操作将生成的jsx保存到变量然后放到此处
          //这里使用了index当作对应的id,实际情况下,尽量还是给对应的数值设置唯一的id,避免特殊情况
      {checks.map((e, index) => {
        return (
          <div key={index}>
            <span>{e.content}</span>
            <input
              type="checkbox"
              value={e.content}
              checked={e.checked}
              onChange={() => handelChange(index)}
            ></input>
          </div>
        );
      })}
    </div>
  );
}

export default Tset;

非受控组件

大多数情况下,在 React 中推荐使用受控组件来对表单进行操作,这样能够对表单控件的数据进行一个统一管理。

但是在某些特殊情况下,需要使用以前传统的 DOM 方案进行处理,此时替代的方案就是非受控组件

首先介绍下类似于vue中的ref绑定dom的方法

在react中,使用 const fileRef = React.createRef();创建一个ref,类似于vue的 ref,仅作用于绑定,不少响应式!!

例子1

 const fileRef = React.createRef();
 <input ref={fileRef} type="file"></input>
通过fileRef可以拿到input的实例

非受控组件默认值

const inputCon = React.createRef();
<div>
  {/* 一旦你用了 value,React 会认为你这是一个受控组件 */}
  {/* 如果想要给默认值,使用 defaultValue */}
  <input type="text" ref={inputCon} defaultValue="123"/>
  <button onClick={this.clickHandle}>获取用户输入的内容</button>
</div>

文件上传


import React from "react";
// 类组件
const uploadRef = React.createRef();
function clickHandle() {
    console.log(uploadRef.current.files);
  }
return (
      <div>
        <input type="file" ref={uploadRef}/>
        <button onClick={clickHandle}>获取用户输入的内容</button>
      </div>
    )

export default App;

组件通信

最常用的莫过于props了,在初始模板我们很容易看到function中存在着props

import React from 'react';

function App(props) {
  return (
    <div>
      
    </div>
  );
}

export default App;
这个props就是为了接收参数而来的

相比vue的组件通讯,react似乎要舒服一点

父组件:
import React from "react";
import Child from "../component/child";
import { useState } from "react";

function App(props) {
  const [dataList, setDataList] = useState([
    {
      id: "01",
      name: "dz1",
      age: 20,
    },
    {
      id: "02",
      name: "dz2",
      age: 20,
    },
    {
      id: "03",
      name: "dz3",
      age: 20,
    },
  ]);
  function AddDataList(val) {
    setDataList((e) => {
       ~~~再次注意,请不要对元数据进行操作,如果有必要,请先保存一份然后操作后覆盖掉元数据
      let neList = [...e];
      neList.push(val);
      return neList;
    });
  }
  return (
    <div>
          //直接在子组件标签上写对应要传递的属性即可
      <Child dataList={dataList} AddDataList={AddDataList}></Child>
    </div>
  );
}

export default App;



子组件:
import React from "react";

function child(props) {
  let list = props.dataList;
    //子组件通过props进行接收
  let show = list.map((e) => {
      //渲染数据展示出来
    return (
      <ul key={e.id}>
        <li>
          {e.name} {e.age}
        </li>
      </ul>
    );
  });
  function add() {
      //仿造子传夫情况,子组件获取一部分数据,传递给父组件,父组件调用自己的方法拿到子组件的数据
    let obj = {
      id: Math.random(),
      name: `${Math.floor(Math.random() * 10)}asd`,
      age: Math.floor(Math.random()) * 10,
    };
    props.AddDataList(obj);
  }
  console.log(props);
  return (
    <div>
      {show}
      <button onClick={add}>点我增加一条数据</button>
    </div>
  );
}

export default child;




QQ20240428115419-ezgif.com-video-to-gif-converter.gif

react-router

index.js
import { BrowserRouter,HashRouter } from "react-router-dom"; //history 模式,HashRouter 哈希模式
   <BrowserRouter>
      <App />
    </BrowserRouter>
使用模式的时候需要讲app外侧进行包裹,以开启指定的模式

路由配置 一
import { NavLink,Routes,Route } from "react-router-dom";  //导航按钮,导航配置,导航设置

 <NavLink to="/home" className="navigation">   //navlink就是router-link,做导航按钮使用
                  主页
 </NavLink>

<Routes>
          <Route path="/home" element={<Home />} />
          <Route path="/add" element={<Add />} />
          <Route path="/about" element={<About />} />
          <Route path="/detail/:id" element={<Detail />} />
          <Route path="/edit/:id" element={<Add />} />
          <Route path="/" element={<Navigate replace to="/home" />} />
</Routes> 


方法二
新建route文件,新建route.js
import React from "react";
import { Navigate, useRoutes } from "react-router-dom";  //navigate 做重定向使用 useRoutes用来写路由配置
import Add from "../components/Add";
import Home from "../components/Home";
import About from "../components/About";
import Detail from "../components/Detail";
import Emil from "../components/Emil";
function Route(props) {
  return useRoutes([
    {
      path: "/home",
      element: <Home />,
    },
    {
      path: "/add",
      element: <Add />,
    },
    {
      path: "/about",
      element: <About />,
      children: [
        {
          path: "emil",
          element: <Emil></Emil>,
        },
      ],
    },
    {
      path: "/detail/:id",
      element: <Detail />,
    },
    {
      path: "/edit/:id",
      element: <Add />,
    },
    {
      path: "/",
      element: <Navigate replace to="/home"></Navigate>,
    },
  ]);
}

export default Route;

在app.jsx里
import RouteConfig from "./route/route";  引入刚刚配置的route文件
使用
  <RouteConfig></RouteConfig>  表示路由显示的位置

子路由展示与编程式与导航参数导航
import { NavLink, useNavigate, Outlet } from "react-router-dom";
NavLink //导航组件  useNavigate返回一个路由器,通过路由器控制编程路由  outlet 子路由展示区域
 let navgite = useNavigate();
  function toEmli() {
    navgite("/about/emil"); //进行路由跳转
  }
  <h1 className="page-header">使用说明</h1>
      <p>学习reatc-router</p>
      <span onClick={toEmli}>点击进入emil</span>
      <NavLink to="/about/emil">进入emli</NavLink>
      {/* 用于在父组件子路由的展示 */}
      <Outlet></Outlet>
路由参数与获取路由参数
使用编程时导航进行路由跳转,同时增加路由参数
 navigate("/home", {
        state: {
          alert: "学生删除成功",
          type: "info",
        },
      });
import { useLocation } from "react-router-dom";
//useLocation 返回路由信息
  let location = useLocation();
location.state  //获取路由传来的参数
//导航组件传递参数
 <NavLink to={`/detail/${e.id}`}>详细</NavLink>
   {  注意在路由配置里面的写法
      path: "/detail/:id",
      element: <Detail />,
    },

react-redux+react-toolkit


安装
npm i @reduxjs/toolkit react-redux

index.js 配置

import { Provider } from "react-redux";  引入provider包裹app,并且将store传递下去
import store from "./store/store";
root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

store.js

import { configureStore } from "@reduxjs/toolkit"; //引入创建仓库
import toDoList from "./todoListSlice";   //引入仓库切片
export default configureStore({
  //传入配置对象
  reducer: {
    todo: toDoList,
  },
});
todoList.js

import { createSlice ,createAsyncThunk} from "@reduxjs/toolkit";   //创建切片
//创建切片
//createAsyncThunk 写异步操作发请求的
export const toDoList = createSlice({
  name: "todoList", //类似仓库名,命名空间
  initialState: {
    //书写仓库数据
    list: {
      name: "asd",
      age: 20,
    },
  },
  //reducers 修改仓库里面的数据方法,类似于action
  reducers: {
    /**
     *
     * @param {*} state 仓库数据
     * @param {*} val 传递过来的数据
     */
 add: (state, { payload }) => {
      //允许直接修改数据
      state.list[0].age = state.list[0].age + payload;
      console.log("state", state, "val", payload);
    },
    changes2: (state, { payload }) => {
      console.log(payload);
      state.list.push(payload);
    },
  },
});
 console.log(toDoList.reducer, toDoList.actions);
// 切片上的reducer是一个函数,会提供仓库的数据,仓库的方法在actions中
export default toDoList.reducer;


app.js  使用仓库数据

import { useSelector } from "react-redux";
function App() {
  let { list } = useSelector((state) => {
    console.log("state", state);   //拿到仓库的数据
    return state.todo;
  });
  const list2 = list.map((e) => {
    return (
      <ul key={e.name}>
        <li>{e.name}</li>
        <li>{e.age}</li>
      </ul>
    );
  });
    
    
 使用action方法
 import { useDispatch } from "react-redux";
import { add, changes2 } from "./store/todoListSlice";
let dispatch = useDispatch(); 调用useDispatch返回一个dispatch方法,使用这个方法调用函数
  function changeAge(val) {
    dispatch(add(val));
    let obj = { name: Math.random(), age: val * 10 };
    dispatch(changes2(obj));
  }

例子

简易版学生管理系统


网站公告

今日签到

点亮在社区的每一天
去签到