二十三、React Router 6

(一)React Router 6 简介

1.Routes

  • v6 新组件
  • 作用和 v5 的 Switch 类似,用于 Route 的容器
  • Route 只有一个会被匹配,且必须定义 Routes

2.Route

  • componentrenderchildren 都变了
  • 需要通过 element 来指定要挂载的组件

郁子大约 4 分钟笔记React18React Router 6李立超
二十四、案例:权限管理

(一)创建案例框架

1. src/index.js

import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter as Router } from "react-router-dom";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <Router>
    <App />
  </Router>,
);

郁子大约 13 分钟笔记React18李立超
二十五、React Hooks

(一)useMemo

  • 引入 useMemo() 解决 sum() 执行过慢导致 count 增加慢的问题
  • 作用:缓存函数执行结果
    • useCallback() 缓存函数对象本身
  • 组件也是函数,可以缓存组件渲染结果

1. src/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 />);

郁子大约 5 分钟笔记React18Hooks李立超
十、React.memo
  • React.memo() 是一个高阶组件
    • 接收另一个组件作为参数,并且返回一个包装后的新组件
    • 新的组件具有缓存功能,只有组件 props 发生变化时才会重新渲染,否则总是返回缓存中的结果
  • 适用于数据较多加载较缓慢的组件

(一) src/index.js

import ReactDOM from "react-dom/client";
import { App } from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(<App />);

郁子小于 1 分钟笔记React18李立超
十一、useCallback
  • onAdd 导致 A 组件的 props 一定会变化, memo 无效,可以使用 useCallback()
  • useCallback() 是一个钩子函数,用来创建 React 中的回调函数
    • 该回调函数不会总在组件重新渲染时重新创建
  • 参数
    • 回调函数
    • 依赖数组
      • 当依赖数组中的变量发生变化时,回调函数才会重新创建
      • 如果不指定依赖数组,回调函数每次都会重新创建
      • 一定要将回调函数中使用到的所有变量都设置到依赖数组中,除了 setState

郁子大约 1 分钟笔记React18李立超
十二、使用fetch获取数据
  • fetch() 用于向服务器发送请求加载数据,是 Ajax 的升级版
  • 需要两个参数
    • 请求地址
    • 请求信息

(一) src/index.js

import ReactDOM from "react-dom/client";
import { App } from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(<App />);

郁子大约 1 分钟笔记React18李立超
十三、数据加载提示和处理错误

(一) src/App.jsx

import React, { useEffect, useState } from "react";
import { StudentList } from "./components/StudentList";
import "./App.css";

// const STU_DATA = [
//   {
//     id: "1",
//     attributes: {
//       name: "张三",
//       age: 18,
//       gender: "男",
//       address: "aaa",
//     },
//   },
//   {
//     id: "2",
//     attributes: {
//       name: "李四",
//       age: 28,
//       gender: "女",
//       address: "bbb",
//     },
//   },
//   {
//     id: "3",
//     attributes: {
//       name: "王五",
//       age: 38,
//       gender: "男",
//       address: "ccc",
//     },
//   },
// ];

export const App = () => {
  // 学生数据
  // const [stuData, setStuData] = useState(STU_DATA);
  const [stuData, setStuData] = useState([]);
  // 记录数据是否正在加载
  const [loading, setLoading] = useState(false);
  // 记录错误信息
  const [error, setError] = useState(null);

  useEffect(() => {
    // 加载数据
    setLoading(true);
    setError(null);
    fetch("http://localhost:1337/api/students")
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        setStuData(data.data);
        setLoading(false);
      })
      .catch((err) => {
        alert(err);
      });

    // 模拟请求出错
    // fetch("http://localhost:1337/api/student")
    //   .then((response) => {
    //     // 判断是否正常返回响应信息
    //     if (response.ok) return response.json();
    //     // 没有成功加载到数据
    //     setLoading(false);
    //     // 抛出错误
    //     throw new Error("数据加载失败");
    //   })
    //   .then((data) => {
    //     setStuData(data.data);
    //     setLoading(false);
    //   })
    //   .catch((err) => {
    //     // catch一执行,说明上述代码出错了
    //     // 统一处理错误
    //     setLoading(false);
    //     setError(err);
    //   });
  }, []);

  return (
    <div className="app">
      {!loading && !error && <StudentList students={stuData} />}
      {loading && <p>数据正在加载中...</p>}
      {error && <p>数据加载异常!</p>}
    </div>
  );
};

郁子大约 1 分钟笔记React18李立超
十四、使用await

(一) src/App.jsx

import React, { useEffect, useState } from "react";
import { StudentList } from "./components/StudentList";
import "./App.css";

export const App = () => {
  // 学生数据
  const [stuData, setStuData] = useState([]);
  // 记录数据是否正在加载
  const [loading, setLoading] = useState(false);
  // 记录错误信息
  const [error, setError] = useState(null);

  // useEffect()参数不能是异步函数
  useEffect(() => {
    const fetchData = async () => {
      try {
        setLoading(true);
        setError(null);
        const res = await fetch("http://localhost:1337/api/students");
        if (res.ok) {
          const data = await res.json();
          setStuData(data.data);
        } else {
          throw new Error("数据加载失败!");
        }
      } catch (error) {
        setError(error);
      } finally {
        setLoading(false);
      }
    };
    fetchData();
  }, []);

  return (
    <div className="app">
      {!loading && !error && <StudentList students={stuData} />}
      {loading && <p>数据正在加载中...</p>}
      {error && <p>数据加载异常!</p>}
    </div>
  );
};

郁子小于 1 分钟笔记React18李立超
十五、删除数据

(一) src/App.jsx

import React, { useCallback, useEffect, useState } from "react";
import { StudentList } from "./components/StudentList";
import StudentContext from "./store/StudentContext";
import "./App.css";

export const App = () => {
  // 学生数据
  const [stuData, setStuData] = useState([]);
  // 记录数据是否正在加载
  const [loading, setLoading] = useState(false);
  // 记录错误信息
  const [error, setError] = useState(null);

  const fetchData = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);
      const res = await fetch("http://localhost:1337/api/students");
      if (res.ok) {
        const data = await res.json();
        setStuData(data.data);
      } else {
        throw new Error("数据加载失败!");
      }
    } catch (error) {
      setError(error);
    } finally {
      setLoading(false);
    }
  }, []);

  // useEffect()参数不能是异步函数
  useEffect(() => {
    fetchData();
  }, [fetchData]);

  const loadData = () => {
    fetchData();
  };

  return (
    <StudentContext.Provider value={{ fetchData }}>
      <div className="app">
        <button onClick={loadData}>加载数据</button>
        {!loading && !error && <StudentList students={stuData} />}
        {loading && <p>数据正在加载中...</p>}
        {error && <p>数据加载异常!</p>}
      </div>
    </StudentContext.Provider>
  );
};

郁子大约 1 分钟笔记React18李立超
十六、添加数据

(一) src/components/StudentList/index.jsx

import React from "react";
import Student from "../Student";
import StudentForm from "../StudentForm";

const StudentList = (props) => {
  return (
    <table>
      <caption>学生列表</caption>
      <thead>
        <tr>
          <th>姓名</th>
          <th>性别</th>
          <th>年龄</th>
          <th>地址</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        {props.students.map((stu) => {
          return <Student key={stu.id} stu={stu} />;
        })}
      </tbody>
      <tfoot>
        <StudentForm />
      </tfoot>
    </table>
  );
};

export default StudentList;

郁子大约 1 分钟笔记React18李立超
2
3