# react
**Repository Path**: Suger-ay/react
## Basic Information
- **Project Name**: react
- **Description**: 学习笔记
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2025-12-10
- **Last Updated**: 2025-12-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
React 学习笔记(React + Vite)
React 官网:https://zh-hans.react.dev/
Vite 官网:https://cn.vitejs.dev/
ReactRouter 官网:https://reactrouter.com/start/modes
##### 1. 创建项目
```bash
npm create vite@latest
```
##### 2. 目录结构
```jsx
// 这里定义的是全局常/变量,不会触发热更新
function App() {
// 热更新js代码区
return(
;
)
}
```
##### 3. 组件
一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图 UI,渲染组件只需要把组件当成标签即可,组件可以嵌套和复用。
##### 4. Hook
- 4.1 useState 状态变量
react 中的状态始终被认为是只读的,不能直接修改,否则不会触发视图更新,需要通过 setState 方法重新赋值。
useState 返回一个数组,第一个值为状态变量,第二个值为修改状态变量的方法。
```jsx
// 表单受控绑定
const [value, setValue] = useState('')
setValue(e.target.value)} />
```
- 4.2 useRef 获取/操作 DOM 元素
useRef 返回一个对象,对象中有一个 current 属性,可以用来获取 DOM 元素,也可以用来存储数据,不会触发视图更新。
```jsx
// 获取DOM元素
const inputRef = useRef(null)
// 以下需考虑生命周期
console.log('拿到的DOM对象:'+inputRef.current)
// 聚焦
inputRef.current?.focus()
```
- 4.3 useEffect 副作用
useEffect 是一个副作用钩子,可以在组件渲染完毕后执行一些额外的操作,比如发送请求、订阅事件、修改 DOM 等。
useEffect 接受两个参数,第一个参数是一个函数,第二个参数是一个数组,数组中的元素是依赖项,当依赖项发生变化时,会重新执行 useEffect 中的函数,当是一个空数组的时候,副作用函数只会在数组渲染完成后执行一次。
```jsx
// 依赖项为空数组,只执行一次
useEffect(() => {
console.log("组件渲染完毕");
}, []);
```
关于依赖项特别说明:
| 依赖项 | 副作用函数执行时机 |
| :------------: | :-------------------------------: |
| 没有依赖项 | 组件初始渲染+组件更新时执行 |
| 空数组依赖 | 只在初始渲染时执行一次 |
| 添加特定依赖项 | 组件初始渲染+特性依赖项变化时执行 |
```jsx
import {useEffect, useState } from "react"
function App{
const[count,setCount]=useState(0)
// 1.没有依赖项 初始 + 组件更新
// useEffect(() => {
// console.log("副作用函数执行了")
// })
// 2.传入空数组依赖 初始执行一次
// useEffect(()=> {
// console.log("副作用函数执行了")
// },[])
// 3.传入特定依赖项初始 + 依赖项变化时执行
useEffect(()=>{
console.log("副作用函数执行了")
},[count])
return (
this is app
)
}
export default App
```
清除副作用
useEffect 返回一个函数,可以在组件卸载时执行一些清理操作,比如取消订阅、清除定时器等。
```jsx
useEffect(() => {
// 执行副作用函数
return () => {
// 清除副作用函数 最常见的执行时机是组件卸载时自动执行
};
});
```
自定义 Hook
名称以 use 开头,抽取可复用的逻辑,方便在组件中使用。
```jsx
import { useState } from "react";
function useToggle() {
// 可复用的代码逻辑
const [value, setValue] = useState(true);
const toggle = () => {
setValue(!value);
};
// return需要在组件中使用的状态和回调函数 []或{}
return [value, toggle];
}
function App() {
// 使用自定义 Hook
const [value, toggle] = useToggle();
return (
{value &&
this is a div
}
);
}
```
封装自定义 Hook 通用思路:
- 1. 定义一个函数,函数名称以 use 开头
- 2. 函数内部封装可复用的逻辑
- 3. 返回需要复用的状态和回调函数
- 4. 在组件中解构自定义 Hook 返回的状态和回调函数,并使用
**Hooks 使用规则说明:**
- 1. 只能在组件或其他自定义 Hook 函数中使用
- 2. 只能在组件顶层使用,不能嵌套在 if、for、try、其他函数中使用
##### 5. 组件通信
- 5.1 父传子
父组件通过 props 传递数据给子组件,子组件通过 props 接收数据。
props 可以传递任意类型的数据,包括字符串、布尔值、函数、对象、数组、JSX 等。
```jsx
// 父组件
function Parent() {
const [value, setValue] = useState("父组件传递的数据");
return (
);
}
// 子组件
function Child(props: { value: string }) {
return {props.value}
;
}
```
props 是只读的,不能直接修改,父组件的数据只能由父组件修改。
**props children**
```jsx
// 父组件 标签嵌套
我是span标签
;
// 子组件 通过props.children渲染在页面中
function Son(props: { children: React.ReactNode }) {
return (
我是子组件
{props.children}
);
}
```
- 5.2 子传父
子组件通过 props 传递数据给父组件,父组件通过 props 接收数据,并传递给子组件。
```jsx
// 父组件
function Parent() {
const [value, setValue] = useState("");
const handleChildChange = (value: string) => {
setValue(value);
};
return (
);
}
// 子组件
function Child(props: { onChange: (value: string) => void }) {
const [value, setValue] = useState("");
const handleChange = (e: React.ChangeEvent) => {
setValue(e.target.value);
props.onChange(e.target.value);
};
return (
);
}
```
- 5.3 兄弟组件
使用状态提升实现兄弟组件通信,即通过共同的父组件传递
```jsx
// 父组件
function Parent() {
const [value, setValue] = useState("");
const handleChildChange = (value: string) => {
setValue(value);
};
return (
);
}
// 子组件1
function Child1(props: { onChange: (value: string) => void }) {
const [value, setValue] = useState("");
const handleChange = (e: React.ChangeEvent) => {
setValue(e.target.value);
props.onChange(e.target.value);
};
return (
);
}
// 子组件2
function Child2(props: { value: string }) {
return (
);
}
```
- 5.4 跨层组件通信——Context 机制
```jsx
// 1. 创建Context
const MyContext = createContext();
// 2. 顶层组件通过Provider组件提供数据
function Parent() {
const [value, setValue] = useState("");
const handleChildChange = (value: string) => {
setValue(value);
};
return (
);
}
// 3. 子组件通过useContext钩子获取数据
function Child2() {
const value = useContext(MyContext);
return (
);
}
```
- 5.5 跨层组件通信——Redux 机制 (集中状态管理工具)
```jsx
// 1. 安装
// Redux Toolkit:是一套工具集,用于简化 Redux 的书写方式
// react-redux:链接React和Redux的中间件
npm i @reduxjs/toolkit react-redux
// 2. 创建slice store/modules/counterStore.js
import { createSlice } from "@reduxjs/toolkit";
import axios from "axios";
const counterSlice = createSlice({
name: "counter", // 命名空间
// 初始化状态
initialState: {
count: 0
},
// 定义修改状态的方法 同步方法 支持直接修改
reducers: {
increment(state) {
state.count ++;
},
decrement(state) {
state.count --;
},
// 支持传递参数 传递的参数会作为action.payload payload:固定的属性名
addToNum(state,action){
state.count+= action.payload
},
},
});
const channelSlice = createSlice({
name: "channel",
initialState: {
channelList: []
},
reducers: {
// 获取异步数据
setChannel(state,action){
state.channelList = action.payload
}
}
})
// 解构actioncCreater函数
const { increment, decrement,addToNum } = counterSlice.actions;
const { setChannel } = channelSlice.actions;
// 发起异步请求
const getChannelList = () => {
return async (dispatch)=>{
const res = await axios.get("http://localhost:3000/channel");
dispatch(setChannel(res.data))
}
}
const countReducer = counterSlice.reducer;
const channelReducer = channelSlice.reducer;
// 导出方法
export { increment, decrement, addToNum, getChannelList };
export default countReducer;
export default channelReducer;
// 3. 创建store store/index.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counterSlice";
import channelReducer from "./channelSlice";
const store = configureStore({
reducer: {
counter: counterReducer,
channel: channelReducer,
},
});
export default store;
// 4. 在顶层组件中提供store App.js
import { Provider } from "react-redux";
import store from "./store";
createRoot(document.getElementById("root")).render(
);
// 5. 在子组件中获取store中的数据 useSelector:映射store中的数据 useDispatch:分发action
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement, addToNum, getChannelList } from "./counterSlice";
function Counter() {
// 获取store中的数据
const count = useSelector((state) => state.counter);
const list= useSelector((state) => state.channel);
const dispatch = useDispatch();
// 触发请求
useEffect(()=>{
dispatch(getChannelList())
},[dispatch])
return (
{count}
{/* 传参 */}
{/* 数据列表 */}
{list.map((item) => (
- {item.name}
))}
);
}
```
##### 6. 路由——ReactRouter
```js
// 1. 安装 v7 https://reactrouter.com.cn/
npm install react-router
// 2.创建路由并绑定组件 router/index.js
import { createBrowserRouter } from "react-router";
import Index from "../page/Index";
const router = createBrowserRouter([
// 普通路由
{
path: "/",
Component: Index,
},
// 嵌套路由
{
path: "/user",
Component: User,
children: [
{
// path: "login",
index: true,// 默认路由
Component: Login,
},
{
path: "register",
Component: Register,
},
]
}
]);
export default router;
// 3. 使用路由 main.js
import { RouterProvider } from "react-router/dom";
import router from "./router/index.js";
createRoot(document.getElementById("root")).render(
{/* */}
{/* 绑定路由 */}
);
// 嵌套
// 3.1 父组件
import { Outlet } from "react-router";
import { Link } from "react-router";
function User() {
return (
用户
登录
注册
{/* 二级路由出口 */}
);
}
// 4. 路由导航
// 4.1 Link
import { Link } from "react-router";
首页
关于
// 4.2 NavLink 需要渲染活跃和待处理状态的导航链接
// https://reactrouter.com/start/framework/navigating#navlink
import { NavLink } from "react-router";
// className
[
isPending ? "pending" : "",
isActive ? "active" : "",
isTransitioning ? "transitioning" : "",
].join(" ")
}
>
Messages
// 4.3 Form
// 4.4 重定向redirect
import { redirect } from "react-router";
export async function loader({ request }) {
let user = await getUser(request);
if (!user) {
return redirect("/login");
}
return { userName: user.name };
}
// 4.5 编程式 useNavigate
import { useNavigate } from "react-router";
export function useLogoutAfterInactivity() {
let navigate = useNavigate();
useFakeInactivityHook(() => {
navigate("/logout");
// 使用navigate函数并设置replace为true来替换当前历史记录
navigate("/logout", { replace: true });
});
}
//4.6 路由导航传参
// 4.6.1 searchParams传参
navigate("/user?id=123");
// 取
const [params]=useSearchParams();
let id=params.get("id");
// 4.6.2 params传参
navigate("/user/123");
// 取
const [params]=useParams();
let id=params.id;
```