React 是一个用于构建用户界面的 JavaScript 库,主要用于构建单页应用(SPA)。由 Facebook 维护。它的核心思想是将 UI 拆分成多个小的、可复用的组件,通过组合这些组件来构建复杂的界面。
核心特性:
组件化开发(Component-Based):将页面拆分成多个独立的组件,每个组件负责一个特定的功能或 UI 部分,提高代码的可维护性和复用性。
虚拟 DOM(Virtual DOM):是 React 使用的轻量级 JavaScript 对象,用来描述 DOM 结构。React 通过对比新旧虚拟 DOM 的差异,只更新需要更新的真实 DOM 节点,减少直接操作 DOM 的次数,提高性能。
单向数据流(One-way Data Flow):数据的流动是单向的,使得数据的流向更加清晰,便于调试和维护。
声明式编程(Declarative UI):通过描述 UI 的最终状态,而不是如何去实现这个状态,让代码更加简洁和易于理解。
JSX 语法扩展:允许在 JavaScript 代码中写 HTML,使代码更直观,便于理解 UI 结构,同时支持变量、函数表达式。
const Hello = () => <h1>Hello, React!</h1>;
JSX 是 JavaScript 的语法扩展,允许你在 JavaScript 代码中写 HTML。它并不是一种新的语言,而是一种语法糖,最终会被 Babel 转译为 React.createElement ()。
好处:
const name = '小明';
const greet = <h1>你好,{name}!</h1>;
1、函数组件(Function Component) ✅ 推荐
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Hook 是 React 16.8 引入的特性,使函数组件具备状态管理和副作用处理的能力,解决了类组件的一些问题,如代码复用困难、状态逻辑复杂等。
- useState:声明状态,允许在函数组件中使用状态。
- import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>点击次数:{count}</p>
<button onClick={() => setCount(count + 1)}>点击我</button>
</div>
);
}
useEffect(() => {
console.log("组件挂载");
return () => console.log("组件卸载");
}, []);
- useRef:引用dom或者保存一些可变值,在组件的整个生命周期内保持不变
import { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>聚焦输入框</button>
</>
);
}
import { useMemo, useCallback } from 'react';
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useEffect 处理副作用逻辑,类似于生命周期函数。它可以在组件渲染后执行一些操作,如数据获取、订阅事件、手动修改 DOM 等。
useEffect(() => {
console.log("组件渲染");
});
useEffect(() => {
console.log("组件渲染");
return{
//componentWillUnmount
}
});
useEffect(() => {
console.log("组件挂载");
return () => console.log("组件卸载");
}, []);
useEffect(() => {
console.log("依赖变化");
}, [dependency]);
总结对比表
依赖数组 | 执行时机 | 适用场景 | 风险提示 |
---|---|---|---|
不传(undefined) | 每次渲染(包括首次和更新) | 无依赖的副作用(如强制刷新)类似于 componentDidMount 和 componentDidUpdate。 | 可能导致性能问题 |
空数组([]) | 仅挂载和卸载时执行一次 | 初始化操作、订阅、清理副作用类似(componentDidMount)。 | 需确保无隐式依赖 |
非空数组 | 依赖项变化时执行 | 同步数据变化的副作用(如网络请求) 类似于(componentDidUpdate) | 需完整声明所有依赖 |
React 使用 map() 方法来渲染数组。key 是一个特殊的属性,它帮助 React 标识哪些元素更改、添加或删除,从而提高渲染性能。
const list = ['a', 'b', 'c'];
<ul>
{list.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
import { useState } from 'react';
function ControlledInput() {
const [value, setValue] = useState('');
return (
<input value={value} onChange={e => setValue(e.target.value)} />
);
}
import { useRef } from 'react';
function UncontrolledInput() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
console.log(inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} type="text" />
<button type="submit">提交</button>
</form>
);
}
React 事件命名采用小驼峰命名法,例如 onClick。事件处理函数通过属性传递给组件,事件对象是合成事件,它在不同浏览器中具有一致的接口。
function handleClick(e) {
console.log('点击事件触发', e);
}
<button onClick={(e) => handleClick(e)}>点我</button>
const MyComponent = React.memo((props) => {
return <div>{props.value}</div>;
});
适用场景
1、纯展示型组件
组件仅依赖传入的 props,无内部状态(useState)或副作用(useEffect),且无需频繁更新。
const Display = React.memo(({ text }) => {
console.log('Render:', text);
return <div>{text}</div>;
});
2、列表项组件
在长列表中,使用react。memo可避免音符组件重新渲染导致的列表项重复渲染
```javascript
const ListItem = React.memo(({ item }) => {
return <div>{item.name}</div>;
});
3、需要优化的复杂计算组件
组件包含复杂的逻辑或计算,但仅依赖稳定的props,可通过react。memo缓存结果
**import React, { useState } from 'react';
// 定义函数组件
const MyComponent = ({ name }) => {
console.log('Component rendered');
return <div>{name}</div>;
};
// 使用 React.memo 包装组件
const MemoizedComponent = React.memo(MyComponent);
// 或直接内联使用
export default function App() {
const [count, setCount] = useState(0);
return (
<>
<MemoizedComponent name="Alice" />
<button onClick={() => setCount(count + 1)}>Rerender Parent</button>
</>
);
}**
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function Home() {
return <h1>主页</h1>;
}
function About() {
return <h1>关于页面</h1>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</BrowserRouter>
);
}
Redux 是一个状态管理库,适合在中大型应用中使用。它采用单向数据流的设计思想,将应用的所有状态集中管理,使得状态的变化可预测和可追溯。
核心概念:
结合 React 示例:
- // store.js
import { createStore } from 'redux';
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case 'INCREMENT': return { count: state.count + 1 };
default: return state;
}
};
const store = createStore(reducer);
// App.js
import { Provider, 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>
);
}
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
Context 用于解决多层组件传值(props drilling)的问题,允许在组件树中共享数据,而不必显式地通过每个组件传递 props。类似于vue 中的provide/inject(跨层级组件传值)
示例:
**import { createContext, useContext } from 'react';
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
return <ThemedButton />;
}
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>按钮</button>;
}**
function Parent() {
const message = 'Hello from parent';
return <Child message={message} />;
}
function Child(props) {
return <p>{props.message}</p>;
}
function Parent() {
const handleChildData = (data) => {
console.log('Received data from child:', data);
};
return <Child onData={handleChildData} />;
}
function Child(props) {
const sendData = () => {
props.onData('Data from child');
};
return <button onClick={sendData}>发送数据给父组件</button>;
}
虚拟 DOM 是 React 使用的轻量级 JavaScript 对象,用来描述 DOM 结构。它是真实 DOM 的抽象表示,React 通过对比新旧虚拟 DOM 的差异,只更新需要更新的真实 DOM 节点。
优点:
特性 | React | Vue |
---|---|---|
数据绑定 | 单向数据流 | 双向数据绑定(v-model) |
编程范式 | 函数式(Hooks)、JSX | 模板驱动、选项式(Vue 3 支持组合式) |
虚拟 DOM | 是 | 是 |
状态管理 | Redux、Context、Zustand 等 | Vuex、Pinia |
生态工具 | Next.js、Umi、Remix | Nuxt.js |
学习曲线 | 高(需要理解 JSX、Hooks 等) | 相对较低(上手快) |
Umi 提供约定式与配置式路由:
✅ 约定式路由
项目中 pages/ 目录结构自动映射成路由。
pages/
├── index.tsx => /
├── user.tsx => /user
✅ 配置式路由
在 config/config.ts 中配置:
export default {
routes: [
{ path: '/', component: '@/pages/index' },
{ path: '/user', component: '@/pages/user' },
],
};
技术 / 方法 | 说明 |
---|---|
React.memo | 缓存组件,避免无意义重新渲染 |
useMemo/useCallback | 缓存函数或计算结果 |
shouldComponentUpdate / PureComponent | 控制类组件更新 |
虚拟滚动 | react-window / react-virtualized |
Profiler | React DevTools 中性能分析工具 |
图片优化 | lazyload、webp、CDN |
可视化项目(如 ECharts/AntV)性能瓶颈常在于渲染与数据量:
✅ 技术层面
import { useEffect } from 'react';
import * as echarts from 'echarts';
function ChartComponent() {
useEffect(() => {
const chart = echarts.init(document.getElementById('main'));
const option = {
// 图表配置
};
chart.setOption(option);
const resizeObserver = () => chart.resize();
window.addEventListener('resize', resizeObserver);
return () => {
window.removeEventListener('resize', resizeObserver);
chart.dispose();
};
}, []);
return <div id="main" style={{ width: '600px', height: '400px' }}></div>;
}
错误边界是 React 16 引入的一个特性,用于捕获并处理子组件树中的 JavaScript 错误,防止错误导致整个应用崩溃。错误边界是一个类组件,它定义了 componentDidCatch 或 getDerivedStateFromError 生命周期方法。
示例:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, errorInfo) {
// 可以在这里记录错误日志
console.log(error, errorInfo);
this.setState({ hasError: true });
}
static getDerivedStateFromError(error) {
// 更新 state 以显示错误 UI
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>发生错误,请稍后重试。</h1>;
}
return this.props.children;
}
}
function BuggyComponent() {
throw new Error('模拟错误');
return <div>这是一个有错误的组件</div>;
}
function App() {
return (
<div>
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
</div>
);
}
高阶组件(Higher-Order Component,简称 HOC)是一个函数,它接收一个组件作为参数,并返回一个新的组件。高阶组件是 React 中复用代码和逻辑的一种方式。
用途:
function withLogging(WrappedComponent) {
return class extends React.Component {
componentDidMount() {
console.log(`${WrappedComponent.name} 组件挂载`);
}
componentWillUnmount() {
console.log(`${WrappedComponent.name} 组件卸载`);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
}
function MyComponent() {
return <div>这是一个组件</div>;
}
const LoggedComponent = withLogging(MyComponent);
function App() {
return <LoggedComponent />;
}