React学习笔记

140 阅读18分钟

创建项目

在终端输入 npx create-react-app react-basic 切换到当前项目下,输入npm start

截屏2024-09-08 15.15.45.png 看到这个界面就表示创建成功啦! 截屏2024-09-08 15.18.24.png

认识目录

1.package.json

项目依赖的核心包: react/react-dom最最核心 截屏2024-09-08 15.22.22.png 可执行命令: start是启动的命令 build是打包的命令 截屏2024-09-08 15.23.54.png

2.src

index.js

//项目的入口,从这里开始运行

//react必要的两个核心包
import React from 'react';
import ReactDOM from 'react-dom/client';

//导入项目的根组件
import App from './App';

//吧App根组件渲染到id为root的DOM节点上
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);

app.js

//项目的根组件
//app被引入到index.js ,被index的一些核心代码渲染到public/index.html里面叫做root到div上去
function App() {
  return (
    <div className="App">
      this is app
    </div>
  );
}

export default App;

了解JSX

概念

JSX是javascript和XML(html)的缩写,表示在js代码中编写html模板结构,它是react中编写UI模板的方式。 优势:1.html的声明式子模板写法。2.js的可编程能力 JSX不是标准的js语法是js的扩展浏览器本身不能识别,需要通过解析工具做解析之后才能在浏览器中运行

截屏2024-09-08 15.57.37.png

JSX中使用JS表达式

在JSX中可以通过 大括号语法{}识别 JavaScript中的表达式,比如常见的变量、函数调用、方法调用等等

  1. 使用引号传递字符串
  2. 使用JavaScript变量
  3. 函数调用和方法调用
  4. 使用JavaScript对象
//项目的根组件
//app被引入到index.js ,被index的一些核心代码渲染到public/index.html里面叫做root到div上去
const name = "Katrina";
const getName = () => {
  return "Jack";
};
function App() {
  return (
    <div className="App">
      this is app
      {/* 使用引号传递字符串 */}
      {"halo!"}
      {/* 识别js变量 */}
      {name}
      {/* 函数调用 */}
      {getName()}
      {/* 方法调用 */}
      {new Date().getDate()}
      {/* 使用js对象 */}
      <div style={{ color: "red" }}>this is ...</div>
    </div>
  );
}

export default App;

JSX中实现列表渲染

语法: 在ISX中可以使用原生JS中的map方法遍历渲染列表

const list = [
  { id: 1, name: "Katrina" },
  { id: 2, name: "Chammy" },
  { id: 3, name: "Winnie" },
];
function App() {
  return (
    <div className="App">
      <ul>{list.map(item => <li key={item.id}>{item.id}:{item.name}</li>)}</ul>
    </div>
  );
}

{/map 循环哪个结构 return结构/} {/* 注意事项:加上一个独一无二的key 字符串或者number id */} key的作用:React框架内部使用 提升更新性能的

JSX实现条件渲染

语法:在React中,可以通过逻辑与运算符&&、三元表达式(?:)实现基础的条件染

const isLog = false;
function App() {
  return (
    <div className="App">
      {/* 逻辑与 */}
      {isLog && <span>this is span</span>}
      {isLog ? <span>jack</span> : <span>loading...</span>}
    </div>
  );
}

JSX中实现复杂条件渲染

需求:列表中需要根据文章状态适配三种情况,单图,三图,和无图三种模式解决方案:自定义函数 +if判断语句

const articleType = 1; //0 1 3
//定义核心函数
function getArticleTem() {
  if (articleType === 0) {
    return <div>我是无图文章</div>;
  } else if (articleType === 1) {
    return <div>我是单图文章</div>;
  } else {
    return <div>我是三图文章</div>;
  }
}
function App() {
  return (
    <div className="App">
      {/* 调用函数 */}
      {getArticleTem()}
    </div>
  );
}

React基础事件绑定

语法:on+事件名称 ={事件处理程序},整体上遵循驼峰命名法

可以拿到事件参数e

const click = (e) => {
  alert("halo啊!");
  //事件参数e
  console.log(e);
};
function App() {
  return (
    <div className="App">
      <button onClick={click}></button>
    </div>
  );
}

image.png

传递自定义参数

语法:事件绑定的位置改造成箭头函数的写法,在执行实际处理函数的时候传递实参

const click = (name) => {
  alert(`${name},halo啊!`);
};
function App() {
  return (
    <div className="App">
      <button onClick={() => click("Katrina")}></button>
    </div>
  );
}

注意:不能直接写函数调用,这里事件绑定需要一个函数引用

既要又要~(同时传递事件对象和自定义参数)

语法:在事件绑定的位置传递事件实参e和自定义参数,click函数中声明形参,注意顺序对应

const click = (name, e) => {
  alert(`${name},halo啊!`);
  console.log(e);
};
function App() {
  return (
    <div className="App">
      <button onClick={(e) => click("Katrina", e)}></button>
    </div>
  );
}

React组件基础使用

React中组件:首字母大写的函数(可以是箭头函数)

内部存放了组件的逻辑和视图U,渲染组件只需要把组件当成标签书写即可

//定义组件
function Button() {
  // 业务逻辑组件逻辑
  return <button>click me!!</button>;
}
function App() {
  return (
    <div className="App">
      {/* 使用组件(渲染组件) */}
      {/* 自闭标签 */}
      <Button />
      {/* 成对标签 */}
      <Button></Button>
    </div>
  );
}

useState

基础使用

useState 是一个React Hook(函数),它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果

本质:和普通JS变量不同的是,状态变量一旦发生变化 组件的视图UI也会跟着变化(数据驱动视图)

  1. useState是一个函数,返回值是一个数组
  2. 数组中的第一个参数是状态变量,第二个参数是set函数(用来修改状态变量)
  3. useState的参数将作为count的初始值
import { useState } from "react";

function App() {
  //useState实现一个计数器按钮
  // count 状态变量
  // setCount 修改状态变量的方法
  const [count, setCount] = useState(0);
  const clickBtn = () => {
    //setCount作用:
    // 1. 传入的新增修改count
    // 2. 重新使用新的count渲染UI
    setCount(count + 1);
  };
  return (
    <div className="App">
      <button onClick={clickBtn}>{count}</button>
    </div>
  );
}

修改状态的规则

在React中,状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

  const [count, setCount] = useState(0);
  const clickBtn = () => {
    //直接修改  无法引发视图更新
    count++;
  };

传过来一个新值之后,这个方法会在内部尝试用这个新值替换旧值,引发视图更新

  const [count, setCount] = useState(0);
  const clickBtn = () => {
    // 传过来一个新值之后,这个方法会在内部尝试用这个新值替换旧值,引发视图更新
    setCount(count + 1);
  };

复杂类型的修改——修改对象状态

规则:对于对象类型的状态变量,应该始终传给set方法一个全新的对象来进行修改

直接修改原对象,不引发视图变化

  const [from, setFrom] = useState({
    name: "jack",
  });
  const clickBtn = () => {
    // 直接修改原对象,不引发视图变化
    from.name = "Katrina";
  };

传入全新对象:

import { useState } from "react";

function App() {
const [from, setFrom] = useState({
  name: "jack",
});
const clickBtn = () => {
  setFrom({
    ...from,
    name: "Katrina",
  });
};
return (
  <div className="App">
    <button onClick={clickBtn}>{from.name}</button>
  </div>
);
}

基础样式控制

组件基础样式方案

React组件基础的样式控制有俩种方式

  1. 行内样式(不推荐)
      <span style={{ color: "red", fontSize: "50px" }}>this is span</span>
      //或
    const style = { color: "red", fontSize: "50px" };
    function App() {
      return (
        <div className="App">
          {/* 行内样式控制 */}
          <span style={style}>this is span</span>
        </div>
      );
    }
  1. class类名控制 index.css中:
.foo {
  color: "red";
  font-size: "50px";
}

App.js中:

import "./index.css";
function App() {
  return (
    <div className="App">
      <span className="foo">this is span</span>
    </div>
  );
}

案例(wei)

classnames优化类名控制(wei)

classnames是一个简单的JS库,可以非常方便的通过条件动态控制class类名的显示 image.png 现在的问题:字符串的拼接方式不够直观,也容易出错 image.png

受控表单绑定(类型vue的v-model)

概念:使用React组件的状态(useState)控制表单的状态 image.png

  1. 准备一个React状态值
  2. 通过value属性绑定状态,通过onChange属性绑定状态同步的函数 通过e拿到输入的最新数据

image.png

React中获取DOM(useRef)

在 React 组件中获取/操作 DOM,需要使用 useRef 钩子函数,分为两步:

  1. 使用useRef创建ref对象,并与JSX绑定 const inputRef = useRef(null)
  2. 在DOM可用时,通过inputRef.current拿到 DOM 对象 console.log(inputRef.current) 渲染完毕之后dom生成之后才可用
import { useRef } from "react";
function App() {
  const inputRef = useRef(null);
  const showDom = () => {
    console.log(inputRef.current);
  };
  return (
    <div>
      <input type="text" ref={inputRef}></input>
      <button onClick={showDom}>获取dom</button>
    </div>
  );
}

组件通信

父传子

基础实现

props说明

chilren说明

子传父

使用状态提升实现兄弟组件通信

使用context机制跨层传递数据

useEffect

概念理解和基础使用

useEfect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作,比如发送AJAX请求,更改DOM等等 image.png 说明:上面的组件中没有发生任何的用户事件,组件渲染完毕之后就需要和服务器要数据,整个过程属于“只由渲染引起的操作”

useEffect 的基础使用

需求:在组件渲染完毕之后,立刻从服务端获取频道列表数据并显示到页面中语法: useEffect(() => {},[]) 参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次


import { useEffect, useState } from "react";
const URL = "http://geek.itheima.net/v1_0/channels";
function App() {
  //创建一个状态数据
  const [list, setList] = useState([]);
  useEffect(() => {
    //额外的操作  获取...
    async function getList() {
      const res = await fetch(URL);
      const jsonRes = await res.json();
      console.log(jsonRes);
      setList(jsonRes.data.channels);
    }
    getList();
  }, []);
  return (
    <div>
      {list.map((item) => (
        <li>{item.name}</li>
      ))}
    </div>
  );
}

不同依赖项说明

useEffect副作用函致的执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现

image.png

  1. 没有依赖项 组件初始渲染 + 组件更新时执行
import { useEffect, useState } from "react";
function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    //1.没有依赖项  初始 + 组件更新
    console.log("副作用函数执行");
  });
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+{count}</button>
    </div>
  );
}

image.png 2. 空数组依赖 只在初始渲染时执行一次

import { useEffect, useState } from "react";
function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    //2. 空数组依赖
    console.log("副作用函数执行");
  }, []);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+{count}</button>
    </div>
  );
}

image.png

  1. 添加特定依赖项 组件初始渲染*特性依魏项交化时执行 (跟第一个的区别就是,这个只会由count引发更新,而第一个没有依赖项,不管是count 还是 name,只要让数据重新发生渲染,就会不断执行)
import { useEffect, useState } from "react";
function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    //3. 传入特定依赖项目 初始 + 依赖项变化时执行
    console.log("副作用函数执行");
  }, [count]);
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>+{count}</button>
    </div>
  );
}

image.png

清除副作用

在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用操作,比如在useEffect中开启了一个定时器,我们想在组件卸载时把这个定时器再清理掉,这个过程就是清理副作用

//需求:在Son组件渲染时开启一个定时器,卸载时清除这个定时器
import { useEffect, useState } from "react";
function Son() {
  //1. 渲染时开启一个定时器
  useEffect(() => {
    const timer = setInterval(() => {
      console.log("定时器执行中");
    }, 1000);

    //在里面return一个清除定时器,不然组件卸载后还是会执行
    return () => {
      //清除副作用(组件卸载时)
      clearInterval(timer);
    };
  }, []);
  return <div>this is son</div>;
}

function App() {
  const [show, setShow] = useState(true);
  return (
    <div>
      {show && <Son />}
      <button onClick={() => setShow(false)}></button>
    </div>
  );
}

export default App;

说明:清除副作用的函数最常见的执行时机是在组件卸载时自动执行

自定义Hook实现

//封装自定义hook通用思路 //1.声明一个以use打头的函数 // 2.在函数体内封装可复用的逻辑(只要是可复用的逻辑) // 3.把组件中用到的状态或者回调return出去(以对象或者数组) // 4.在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用


import { useState } from "react";

function useToggle() {
  //可复用代码
  const [value, setValue] = useState(true);
  const toggle = () => setValue(!value);
  //哪些状态和回调函数需要在其他组件中使用 return

  return {
    value,
    toggle,
  };
}

function App() {
  //问题:布尔切换的逻辑 当前组件耦合在一起的  不方便复用
  //解决思路: 自定义hook
  // const [value, setValue] = useState(true);
  // const toggle = () => setValue(!value);

  const { value, toggle } = useToggle();
  return (
    <div>
      {value && <div>this is div</div>}
      <button onClick={toggle}>toggle</button>
    </div>
  );
}

ReactHooks使用规则说明

使用规则

  • 只能在组件中或者其他自定义Hook函数中调用
  • 只能在组件的顶层调用,不能嵌套在if、for、其他函数中

image.png image.png

Redux

什么是Redux

Redux是React最常用的集中状态管理工具,类似于Vue中的Pinia(Vuex),可以独立于框架运行作用:通过集中管理的方式管理应用的状态

使用步骤:
  1. 定义一个 reducer 函数(根据当前想要做的修改返回一个新的状态)
  2. 使用createStore方法传入reducer函数 生成一个store实例对象
  3. 使用store实例的 subscribe方法 订阅数据的变化(数据一旦变化,可以得到通知)
  4. 使用store实例的dispatch方法提交action对象 触发数据变化(告诉reducer你想怎么改数据)
  5. 使用store实例的 getState方法 获取最新的状态数据更新到视图中
Redux管理数据流程梳理

为了职责清晰,数据流向明确,Redux把整个数据修改的流程分成了三个核心概念,分别是:state、action和reducer

  1. state-一个对象 存放着我们管理的数据状态
  2. action-一个对象 用来描述你想怎么改数据
  3. reducer-一个函数 根据action的描述生成一个新的state

image.png

//还没运行起来:

<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<!-- <script src="https://unpkg.com/redux@latest/dist/redux.js"></script> -->
<script src="/node_modules/redux/dist/cjs/redux.cjs"></script>
<script>
  //   import Redux from "/node_modules/redux/dist/redux";
  //1.
  //state:管理的数据初始状态
  //action:对象type标记当前想要做什么样的修改
  function reducer(state = { count: 0 }, action) {
    //数据不可变:基于原始状态生成一个新的状态
    if (action.type === "INCREMENT") {
      return { count: state.count + 1 };
    }
    if (action.type === "DECREMENT") {
      return { count: state.count - 1 };
    }
    return state;
  }
  //2. 使用reducer函数生成store实例
  const store = Redux.createStore(reducer);

  //3.通过store实例的subscribe订阅数据变化
  //回调可以在每次state发生变化的时候自动执行
  store.subscribe(() => {
    console.log("store变化了", store.getState());
    document.getElementById("count").innerText = store.getState().count;
  });

  //4. 通过store实例的dispatch函数提交action更改状态
  const inBtn = document.getElementById("increment");
  inBtn.addEventListener("click", () => {
    //增
    store.dispatch({
      type: "INCREMENT",
    });
  });
  const dBtn = document.getElementById("decrement");
  dBtn.addEventListener("click", () => {
    //减
    store.dispatch({
      type: "DECREMENT",
    });
  });

  //5.通过store实例的getState方法获取最新状态更新到视图中
</script>

Redux与React

环境准备

image.png

  1. 使用 CRA 快速创建 React 项目 npx create-react-app react-redux
  2. 安装配套工具 npm i @reduxjs/toolkit react-redux
  3. 启动项目 npm run start

安装后创建目录 image.png

实现count

整体路径熟悉 image.png

使用React Toolkit创建counterStore

在module/counterStore:

import { createSlice } from "@reduxjs/toolkit";

const counterStore = createSlice({
  name: "counter",
  //初始化state
  initialState: {
    count: 0,
  },
  //修改状态的方法 同步方法 支持直接修改
  reducers: {
    inscrement(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
  },
});

//解构出来actionCreater函数
const { inscrement, decrement } = counterStore.actions;

//获取reducer
const reducer = counterStore.reducer;

//以按需导出的方式导出actionCreater
export { inscrement, decrement };

//以默认导出的方式导出reducer
export default reducer;

在index.js引入:

import { configureStore } from "@reduxjs/toolkit";

//导入子模块reducer
import counterReducer from "./modules/counterStore";

const store = configureStore({
  reducer: {
    conter: counterReducer,
  },
});

export default store;

为React注入store

react-redux负责把Redux和React连接起来,内置 Provider组件 通过 store 参数把创建好的store实例注入到应用中链接正式建立 在src/index.js中:

//在这里导入
import store from "./store";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    {/* 为React注入store */}
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
React组件使用store中的数据

在React组件中使用store中的数据,需要用到一个钩子函数-useSelector,它的作用是把store中的数据映射到组件中,使用样例如下: image.png 在App.js中:

import { useSelector } from "react-redux";

function App() {
  const { count } = useSelector((state) => state.counter);
  return <div className="App">{count}</div>;
}

export default App;

React组件修改store中的数据

React组件中修改store中的数据需要借助另外一个hook函数-useDispatch,它的作用是生成提交action对象的dispatch函数,使用样例如下: image.png 在App.js里面导入useDispatch,导入之前actionCreater里面的,,,,

import { useDispatch, useSelector } from "react-redux";

//导入actionCreater
import { inscrement, decrement } from "./store/modules/counterStore";

function App() {
  const { count } = useSelector((state) => state.counter);
  const dispatch = useDispatch();
  return (
    <div className="App">
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(inscrement())}>+</button>
    </div>
  );
}

export default App;

总结
  1. 组件中使用哪个hook函数获取store中的数据: useSelector
  2. 组件中使用哪个hook函数获取dispatch方法: useDispatch
  3. 如何得到要提交action对象: 执行store模块中导出的actionCreater方法

提交aciton传参

image.png

提交action传参实现需求

在reducers的同步修改方法中添加action对象参数,在调用actionCreater的时候传递参数,参数会被传递到action对象payload属性上

image.png 在counterStore.js里面的reducer里加个addToNum(这时下面的导出也要记得写)

const counterStore = createSlice({
  name: "counter",
  //初始化state
  initialState: {
    count: 0,
  },
  //修改状态的方法 同步方法 支持直接修改
  reducers: {
    inscrement(state) {
      state.count++;
    },
    decrement(state) {
      state.count--;
    },
    addToNum(state, action) {
      state.count = action.payload;
    },
  },
});

在App.js里再引入addToNum,跟之前不同的是,在调用时传入了参数,会自动传递到action.payload交给count。


//导入actionCreater
import { inscrement, decrement, addToNum } from "./store/modules/counterStore";

function App() {
  const { count } = useSelector((state) => state.counter);
  const dispatch = useDispatch();
  return (
    <div className="App">
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(inscrement())}>+</button>
      //这里传入参数:
      <button onClick={() => dispatch(addToNum(10))}>add To 10</button>
      <button onClick={() => dispatch(addToNum(20))}>add To 20</button>
    </div>
  );
}

export default App;

异步操作样板代码(wei)

image.png

  1. 创建store的写法保持不变,配置好同步修改状态的方法
  2. 单独封装一个函数,在函数内部return一个新函数,在新函数中 2.1 封装异步请求获取数据 2.2 调用同步actionCreater传入异步数据生成一个action对象,并使用dispatch提交3.组件中dispatch的写法保持不变 14:48

路由

什么是前端路由: 一个path对应一个组件component,当我们在浏览器中访问一个path时,path对应的组件会被渲染 image.png

创建路由开发环境

1.创建项目并安装所有依赖 npx create-react-app react-router-pro 2.安装最新的 ReactRouter包npm i react-router-dom 3.启动项目 npm run start

快速开始

需求:创建一个可以切换登录页和文章页的路由系统

image.png 在src/index.js中:

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

//导入
import { createBrowserRouter, RouterProvider } from "react-router-dom";

//1. 创建router实例对象并且配置路由对应关系
const router = createBrowserRouter([
  {
    path: "/login",
    element: <div>我是登录页</div>,
  },
  {
    path: "/article",
    element: <div>我是文章页</div>,
  },
]);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    {/* 2.路由绑定 */}
    <RouterProvider router={router}></RouterProvider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

image.png

image.png

抽象路由模块

image.png

创建src/page文件夹

在page里面创建子文件夹Article、Login,在它们的子文件index.js里面写组件 如src/page/Article/index.js:

const Article = () => {
  return <div>我是登录页</div>;
};

export default Article;

创建src/router文件夹

在src/router/index.js里引入组件 配置好对path与组件对应关系,导出实例对象

import Login from "../page/Login";
import Article from "../page/Article";

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

const router = createBrowserRouter([
  {
    path: "/login",
    element: <Login />,
  },
  {
    path: "/article",
    element: <Article />,
  },
]);

export default router;

应用入口文件渲染

在src/index.js中:

//导入
import { RouterProvider } from "react-router-dom";

//1.导入路由router
import router from "./router";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    {/* 2.路由绑定 */}
    <RouterProvider router={router}></RouterProvider>
  </React.StrictMode>
);

路由导航

什么是路由导航

路由系统中的多个路由之间需要进行路由跳转,并且在跳转的同时有可能需要传递参数进行通信

image.png

声明式导航

声明式导航是指通过在模版中通过<Link/>组件描述出要跳转到哪里去,比如后台管理系统的左侧菜单通常使用这种方式进行

文章

语法说明:通过给组件的to属性指定要跳转到路由path,组件会被渲染为浏览器支持的a链接,如果需要传参直接通过字符串拼接的方式拼接参数即可 eg:在src/page/Login/index.js中: (注意Link是首字母大写!)

import { Link } from "react-router-dom";
const Login = () => {
  return (
    <div>
      我是登录页
      <Link to="/article">跳转到文章页</Link>
    </div>
  );
};
export default Login;
编程式导航

通过useNavigate钩子得到导航方法,然后通过调用方法以命令式的形式进行路由跳转,比如想在登录请求完毕之后跳转就可以选择这种方式,更加灵活

image.png 语法说明:通过调用navigate方法传入地址path实现跳转 在src/page/Login/index.js中:

import { Link, useNavigate } from "react-router-dom";
const Login = () => {
  const navigate = useNavigate();
  return (
    <div>
      我是登录页
      {/* 声明式的写法:(常见在菜单里面根据模板进行绑定) */}
      <Link to="/article">跳转到文章页</Link>
      {/* 命令式的写法:(通常会写到js逻辑代码里面,比如登录后要跳转) */}
      <button onClick={() => navigate("/article")}>跳转到文章页</button>
    </div>
  );
};

export default Login;

路由导航传参

searchParmas传参

自己总结就是:

  • 在要传的地址后面加?去传,不同参数用&隔开
  • 在接收的地方导入useSearchParams,通过params拿到。 const [params] = useSearchParams(); const id = params.get("id"); image.png

login/index.js中: <button onClick={() => navigate("/article?id=100&name=jack")}>searchParams image.png 在Article/index.js中接收参数:

import { useSearchParams } from "react-router-dom";
const Article = () => {
  const [params] = useSearchParams();
  const id = params.get("id");
  const name = params.get("name");
  return (
    <div>
      我是文章页{id}-{name}
    </div>
  );
};
export default Article;
params传参
  • 传参时不需要加问号,直接拼接(注意拼接后要回到路由的root的位置加上一个占位符)(要是传多个参数就再加几个相应的占位符)
  • 接收的部分换了一个构造函数,变成了useParams,调用这个方法就可以得到一个对象,通过点语法拿到它里面的参数的值

image.png 在Login/index.js中:

<button onClick={() => navigate("/article/1001")}>Params传参</button>

在路由router/index.js中: (加占位符:id)

  {
    path: "/article/:id",
    element: <Article />,
  },

接收方Article/index.js:

// import { useSearchParams } from "react-router-dom";
import { useParams } from "react-router-dom";
const Article = () => {
  //   const [params] = useSearchParams();
  const id = useParams().id;
  //   const id = params.get("id");
  //   const name = params.get("name");
  return <div>我是文章页{id}</div>;
};
export default Article;

image.png

嵌套路由配置

在一级路由中又内嵌了其他路由,嵌套至一级路由内的路由又称作二级路由 实现步骤:

  1. 使用 children 属性配置路由嵌套关系
  2. 使用<Outlet/>组件配置二级路由渲染位置 image.png

默认二级路由

场景和配置方式

当访问的是一级路由时,默认的二级路由组件可以得到渲染,只需要在二级路由的地址去掉path,设置index属性为ture。 image.png 设置为默认二级路由,一级路由访问的时候,它也能得到渲染

image.png

404路由

场景:当浏览器输入url的路径在整个路由配置中都找不到对应的path,为了用户体验,可以使用404兜底组件进行渲染

实现步骤:
  1. 准备一个NotFound组件
  2. 在路由表数组的末尾,以 * 号作为路由path配置路由 image.png

两种路由模式

image.png P59Day4-08.ReactRouter-俩种路由模式

......

useReducerngji配套gt攻击配套gtjingji配套gt攻击配套ao配套gt攻击配套gtjingji配套gt攻击配套gtji配套gt攻击配套gtjingji配套gt攻击配套ao配套gt攻击配套gtjingji配套gt攻击配套gtoi

useCallback

作用:

[04:38](https://www.bilibili.com/video/BV1ZB4y1Z7o8?p=137 "Day10-05.useCallback")