本文最后更新于 2025年8月25日 晚上
React React 是一个构建用户界面的库,核心思想是组件化 + 状态驱动视图 + 声明式编程 。描述 UI 时应该是什么样子(State -> UI),而不是如何操作 DOM(命令式)。
核心概念
组件 (Component) UI 的最小单元,分为函数组件 和类组件 ,Hooks 出来后基本用函数组件
JSX 一种语法糖,把 HTML 和 JavaScript 混合书写,编译后变成 React.createElement
Props 组件外部传入的数据(最好只读)
State 组件内部管理的数据(可变)
数据流 单向数据流:Props Down、Events Up(数据通过 props 向下传递、事件向上触发)
Hooks(函数组件核心)
useState → 管理组件内部状态
useReducer → 适合管理复杂 state 逻辑(是 useState 的替代方案)
useEffect → 处理副作用(数据获取、订阅、手动操作 DOM)
useContext → 跨组件传递数据,无需组件层层传递,直接读取 Context 值
useMemo / useCallback → 性能优化,缓存函数和计算结果,避免不必要的重渲染
useRef → 获取 DOM 节点或存储任何可变值(.current 属性),变化不会引发重渲染
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { useState, useEffect } from "react" ;export default function (props ) { const { initialName } = props; const [name, setName] = useSate(initialName); const [count, setCount] = useState(0 ); useEffect(() => { document .title = `你点击了 ${count} 次` ; console .log("Count updated:" , count); return () => { console .log("清理副作用" ); }; }, [count]); const handleClick = () => { setCount(count + 1 ); setName(`New Namw` )e }; return ( <div > <h1 > Hello, {name}</h1 > <p > Count: {count}</p > <button onClick ={handleClick} > 点击增加</button > </div > ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import { useState, useEffect } from "react" ;function Parent ( ) { const [data, setData] = useState("父组件自身的数据" ); const handleChildEvent = (childData ) => { console .log("来自子组件的数据" , childData); setData(childData); }; return ( <div > <Child data ={data} onEvent ={handleChildEvent} /> </div > ); }function Child (props ) { const { data, onEvent } = props; return <button onClick ={() => onEvent("子组件自身的数据")}>{data}</button > ; }
Redux 入门 Redux 入门 React Redux
Redux 是 状态管理工具 ,用来管理复杂应用的全局状态。
核心思想
单一数据源 store:全局状态仓库,唯一
状态不可变 state:存储的数据本身
action:一个普通对象,描述“发生了什么”
dispatch:发送 action 的唯一方式
reducer: 纯函数更新,接收 state + action => 返回新 state
核心概念 当使用普通对象来描述应用的 state 时。例如,todo 应用的 state 可能长这样:
1 2 3 4 5 6 7 const state = { todos : [ { text : "Eat food" , completed : true }, { text : "Exercise" , completed : false }, ], visibilityFilter : "SHOW_COMPLETED" , };
state 对象就像 “Model”,区别是它没有 setter(修改器方法)。因此其它的代码不能随意修改它,否则会造成难以复现的 bug。
要想更新 state 中的数据,需要发起一个 action。action 就是一个普通 JavaScript 对象(注意到没,并没有什么魔法?)用来描述发生了什么。下面是一些 action 的示例:
1 2 3 4 5 const actions = [ { type : "ADD_TODO" , text : "Go to swimming pool" }, { type : "TOGGLE_TODO" , index : 1 }, { type : "SET_VISIBILITY_FILTER" , filter : "SHOW_ALL" }, ];
强制使用 action 来描述所有变化可以让清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。actions 就像是描述所发生事情的面包屑导航。最终,开发一个函数将 action 和 state 联系起来,这个函数就是 reducer。同样,这也没有使用什么魔法,reducer 只是一个接收 state 和 action 作为其参数,并返回应用新 state 的函数。对于大的应用来说,不大可能仅仅只写一个这样的函数,所以编写很多小函数来分别管理 state 的一部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function visibilityFilter (state = 'SHOW_ALL' , action ) { if (action.type = 'SET_VISIBILITY_FILTER' ) { return action.filter } else { return state } }function todos (state = [], action ) { switch (action.type) { case 'ADD_TODO' : return state.concat([ text: action.text, completed : false ]); case 'TOGGLE_TODO' : return state.map((todo, index ) => { action.index === index ? { text : todo.text, completed : !todo.completed } : todo }) default : return state } }
再开发一个 reducer,通过调用两个 reducer 来获取相应的状态,进而来管理整个应用 state:
1 2 3 4 5 6 function todoApp (state = {}, action ) { return { todos : todos(state.todos, action), visibilityFilter : visibilityFilter(state.visibilityFilter, action), }; }
这差不多就是 Redux 的全部思想。注意,还没有使用任何 Redux 的 API。Redux 里有一些实用的工具来简化这种模式,但是其主要思想是如何根据 action 对象来更新 state,而且 90% 代码都是普通 JavaScript,没用 Redux 本身、Redux API 或任何魔法。
示例代码 旧写法(connect 高阶组件) 1 2 3 4 5 6 7 8 9 10 11 import { connect } from "react-redux" ;const Counter = ({ count, dispatch } ) => ( <div > <p > {count}</p > <button onClick ={() => dispatch({ type: "increment" })}>+</button > </div > );const mapStateToProps = (state ) => ({ count : state.count });export default connect(mapStateToProps)(Counter);
现代写法(Hooks API) 1 2 3 4 5 6 7 8 9 10 11 12 13 import { useSelector, useDispatch } from "react-redux" ;function Counter ( ) { const count = useSelector((state ) => state.count); const dispatch = useDispatch; return ( <div > <p > {count}</p > <button onClick ={() => dispatch({ type: "increment" })}>+</button > </div > ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 import { createSlice, configureStore } from "@reduxjs/toolkit" ;const counterSlice = createSlice({ name : "counter" , initialState : { value : 0 }, reducers : { incremented : (state ) => { state.value += 1 ; }, decremented : (state ) => { state.value -= 1 ; }, incrementByAmount : (state, action ) => { state.value += action.payload; }, }, });export const { incremented, decremented, incrementByAmount } = counterSlice.actions;const store = configureStore({ reducer : { counter : counterSlice.reducer, }, });import { useSelector, useDispatch } from "react-redux" ;import { incremented, decremented, incrementByAmount } from "Slice" ;function Counter ( ) { const count = useSelector((state ) => state.counter.value); const dispatch = useDispatch(); return ( <div > <span > {count}</span > {/* dispatch 自动生成的 action */} <button onClick ={() => dispatch(incremented())}>+</button > <button onClick ={() => dispatch(decremented())}>-</button > <button onClick ={() => dispatch(incrementByAmount(5))}>+5</button > </div > ); }import { Provider } from "react-redux" ;import ReactDOM from "react-dom" ; ReactDOM.render( <Provider store ={store} > <App /> </Provider > , document .getElementById("root" ) );
Router React Router 主页
React Router 是用来实现 单页面应用 (SPA) 的前端路由。
基本概念
<BrowserRouter>:用 History API 管理路由,包裹整个应用
<Routes>/<Route>:定义路由规则,v6 使用相对路径,规则嵌套更直观
<Link>:导航链接,替代 <a> 标签
useNavigate:替代 useHistory,用于编程式导航
useParams:获取 URL 中的动态参数(如 :id)
useLocation:获取当前 location 对象信息
示例代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import { BrowserRouter, Routes, Route, Link, useParams, useNavigate, } from "react-router-dom" ;function Home ( ) { return <h1 > Home</h1 > ; }function About ( ) { return <h1 > About</h1 > ; }function User ( ) { const { id } = useParams(); return <h1 > User ID: {id}</h1 > ; }export default function App ( ) { const navigate = useNavigate(); return ( <BrowserRouter > <nav > <Link to ="/" > Homw</Link > <Link to ="/about" > About</Link > <Link to ="/user/42" > User 42</Link > </nav > <Routes > <Route path ="/" element ={ <Home /> }></Route > <Route path ="/about" element ={ <About /> }></Route > <Route path ="/user/:id" element ={ <User /> }></Route > </Routes > <button onClick ={() => navigate("/about")}>Go to About</button > </BrowserRouter > ); }