【Web前端】React核心知识点梳理

一、核心概念与基础

1. React 是什么?

一个用于构建用户界面的 JavaScript 库。

核心特点:声明式、组件化、一次学习,随处编写。

2. JSX (JavaScript XML)

// JSX 示例
function Wel***e(props) {
  const name = 'World';
  const isLoggedIn = true;
  const todos = [{ id: 1, text: 'Learn React' }, { id: 2, text: 'Build App' }];

  return (
    <div className="greeting">
      {/* 嵌入表达式 */}
      <h1>Hello, {name}!</h1>
      
      {/* 条件渲染 */}
      {isLoggedIn ? <p>Wel***e back!</p> : <p>Please sign up.</p>}
      {isLoggedIn && <AdminPanel />}
      
      {/* 列表渲染与 key */}
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
    </div>
  );
}

1)定义:一种 JavaScript 的语法扩展,允许在 JS 代码中编写类似 HTML 的结构。

2)特点

① 不是字符串也不是 HTML:最终会被 Babel 等工具编译成 React.createElement() 调用。

② 必须返回一个根元素:早期必须用一个父标签(如 <div>)包裹,现在可以使用 <> (Fragment) 作为空根。

③ 使用 className 代替 classhtmlFor 代替 for(因为它们是 JS 的保留关键字)。

④ 所有标签必须闭合:例如 <img /><input />

⑤ JavaScript 表达式嵌入:使用花括号 {} 可以在 JSX 中嵌入任何有效的 JS 表达式。

3)条件渲染:在 {} 内使用三元运算符 ? : 或 && 逻辑运算符。

4)列表渲染:使用 Array.prototype.map() 方法,并为每个子元素提供一个唯一的 key 属性。

3. 组件

// 函数组件
function My***ponent(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 箭头函数也是常见的写法
const My***ponent = (props) => {
  return <h1>Hello, {props.name}</h1>;
};

// 类组件
class My***ponent extends React.***ponent {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

1)概念:UI 的独立、可复用的片段。React 应用就是由组件树构成的。

2)两种定义方式

① 函数组件(推荐):一个返回 JSX 的普通 JavaScript 函数。

② 类组件:使用 ES6 class 并继承 React.***ponent,必须包含 render() 方法。

4. Props(属性)

// 父组件
function App() {
  return (
    <UserProfile name="Alice" age={30} isVerified>
      <p>This is the user's bio.</p> {/* 这是 children */}
    </UserProfile>
  );
}

// 子组件
function UserProfile({ name, age, isVerified, children }) { // 解构 props
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
      {isVerified && <span>✓ Verified</span>}
      <div>{children}</div> {/* 渲染 bio */}
    </div>
  );
}

1)定义:从父组件向子组件传递数据的只读对象。Props 是只读的,组件决不能修改自身的 props。

2)传递:像 HTML 属性一样在子组件标签上传递。

3)接收:函数组件通过 props 参数接收;类组件通过 this.props 接收。

4)Children Prop:一个特殊的 prop,代表开始标签和结束标签之间的内容,通过 props.children 访问。

5)PropTypes:用于对组件 props 进行类型检查的库(需要单独安装),在大型项目和团队协作中非常有用。

5. State(状态)

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // 基本类型
  const [user, setUser] = useState({ name: 'Bob', age: 25 }); // 对象

  const increment = () => {
    setCount(prevCount => prevCount + 1); // 使用函数式更新,依赖前一个状态
  };

  const updateName = (newName) => {
    setUser(prevUser => ({ ...prevUser, name: newName })); // 正确:创建新对象
    // setUser(prevUser => { prevUser.name = newName; return prevUser; }); // 错误:直接修改!
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={increment}>Click me</button>
      <p>User: {user.name}</p>
    </div>
  );
}

1)定义:组件内部管理、可以变化的数据。状态的改变会驱动组件的重新渲染。

2)useState Hook(函数组件)

① const [state, setState] = useState(initialState);

② setState 是异步的,用于更新状态并触发重新渲染。

③ 状态更新是替换(对于对象/数组):必须使用新的引用来更新。通常使用扩展运算符 ... 或 map/filter 等返回新数组的方法。

6. 事件处理

function Form() {
  const [inputValue, setInputValue] = useState('');

  const handleClick = (e, id) => {
    e.preventDefault();
    console.log('Button clicked with id:', id);
  };

  const handleChange = (e) => {
    setInputValue(e.target.value);
  };

  return (
    <form>
      <input type="text" value={inputValue} onChange={handleChange} />
      {/* 正确:传递函数引用 */}
      <button onClick={(e) => handleClick(e, 1)}>Click Me</button>
    </form>
  );
}

1)命名:采用驼峰式(camelCase),如 onClickonChange

2)传参:通常需要传递一个函数引用,而不是调用函数。

3)阻止默认行为:必须显式调用 e.preventDefault()

4)事件对象:React 封装了浏览器的原生事件对象,称为 SyntheticEvent


二、Hooks(函数组件的核心)

Hooks 让函数组件能够使用 state 和其他 React 特性。

1. useState

如上所述,用于在函数组件中添加状态。

2. useEffect

import { useState, useEffect } from 'react';

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    // 这是一个副作用:获取用户数据
    fetch(`/api/users/${userId}`)
      .then(response => response.json())
      .then(data => setUser(data));

    // 清理函数(可选):例如取消订阅、清除定时器
    return () => {
      console.log('Cleanup for user:', userId);
    };
  }, [userId]); // 依赖项:当 userId 变化时,会重新执行 Effect

  if (!user) return <div>Loading...</div>;
  return <div>Hello, {user.name}</div>;
}

1)作用:用于在函数组件中执行副作用操作(数据获取、订阅、手动修改 DOM 等)。

2)执行时机:在浏览器完成布局与绘制之后,在一个延迟事件中被调用。

3)依赖数组

① 无依赖数组:每次渲染后都执行。

② 空数组 []:只在组件挂载后执行一次(类似于 ***ponentDidMount)。

③ 有依赖的数组 [dep1, dep2]:只在依赖项发生变化后执行(类似于 ***ponentDidUpdate 对特定 props/state 的监听)。

4)清除副作用:Effect 函数可以返回一个清理函数,在组件卸载或执行下一次 Effect 之前运行(类似于 ***ponentWillUnmount)。

3. useContext

// 1. 创建 Context
const ThemeContext = React.createContext('light');

function App() {
  // 2. 使用 Provider 提供 value
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar() {
  // 中间的组件无需传递 theme prop
  return <ThemedButton />;
}

function ThemedButton() {
  // 3. 在子组件中使用 useContext 获取 value
  const theme = useContext(ThemeContext);
  return <button className={theme}>I am styled by theme!</button>;
}

1)作用:无需组件层层嵌套传递 props,就能在组件树中传递数据。用于读取和订阅上下文。

2)流程React.createContext() -> <Context.Provider value={value}> -> useContext(Context)

4. useReducer

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
    </>
  );
}

1)作用useState 的替代方案,适用于状态逻辑复杂、包含多个子值,或者下一个状态依赖于之前状态的场景。灵感来源于 Redux。

2)核心概念(state, action) => newState

5. useMemo & useCallback(性能优化)

function Parent({ a, b }) {
  // 只有当 a 或 b 改变时,expensiveValue 才会重新计算
  const expensiveValue = useMemo(() => {
    let sum = 0;
    for (let i = 0; i < 1000000; i++) {
      sum += a + b;
    }
    return sum;
  }, [a, b]);

  // 只有当 a 改变时,memoizedCallback 的引用才会改变
  const memoizedCallback = useCallback(() => {
    console.log(a);
  }, [a]);

  return (
    <div>
      <p>Value: {expensiveValue}</p>
      <Child onSomething={memoizedCallback} />
    </div>
  );
}

// 使用 React.memo 包装 Child,只有当其 props 变化时才重渲染
const Child = React.memo(({ onSomething }) => {
  // ...
  return <button onClick={onSomething}>Click</button>;
});

1)useMemo:缓存计算结果,避免在每次渲染时都进行高开销计算。

const memoizedValue = useMemo(() => ***puteExpensiveValue(a, b), [a, b]);

2)useCallback:缓存函数本身,避免子组件因函数引用不同而进行不必要的重渲染。它本质上是 useMemo 的语法糖:useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);

6. useRef

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const intervalRef = useRef(); // 用于保存 timer ID

  const onButtonClick = () => {
    // 访问 DOM 元素
    inputEl.current.focus();
  };

  useEffect(() => {
    // 保存 timer ID,不会触发重渲染
    intervalRef.current = setInterval(() => {
      // ...
    }, 1000);
    return () => clearInterval(intervalRef.current);
  }, []);

  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

1)作用

① 访问 DOM 元素:<div ref={myRef} />

② 保存一个在组件的整个生命周期内持久化且变化不会引起重渲染的可变值。

2)current 属性是可变的。


三、高级概念与模式

1. 组件组合 vs 继承

1)React 官方强烈推荐使用组合而非继承来实现组件间的代码复用。

2)包含关系:使用 children prop 或者自定义 prop 来将子组件“注入”到父组件中。

3)特例关系:一个组件是另一个组件的特殊 case,通过配置 props 来实现。

2. 状态提升

当多个组件需要反映相同的变化数据时,建议将共享状态提升到它们最近的共同父组件中。

3. 受控组件 vs 非受控组件

1)受控组件:表单数据由 React 组件状态管理。value 和 onChange 必须一起使用。

2)非受控组件:表单数据由 DOM 自身管理。通常使用 ref 来从 DOM 获取表单值。

4. 代码分割(React.lazy & Suspense)

const Lazy***ponent = React.lazy(() => import('./Lazy***ponent'));

function My***ponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <Lazy***ponent />
      </Suspense>
    </div>
  );
}

1)React.lazy() 允许你动态导入组件,实现按需加载。

2)<Suspense> 组件在懒加载组件加载过程中显示一个回退内容(如 loading 指示器)。

5. 错误边界(Error Boundaries)

1)一个类组件,定义了 static getDerivedStateFromError() 或 ***ponentDidCatch() 生命周期方法中的任何一个(或两个),它就可以成为错误边界。

2)用于捕获其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而不会渲染那些发生崩溃的子组件树。

3)注意:错误边界无法捕获事件处理器、异步代码、服务端渲染等错误。


四、生态系统与工具

1. 路由管理 - React Router

React Router 是 React 生态中最流行的路由解决方案,专门为单页应用(SPA)设计。

1)它提供了一套声明式的路由组件,包括:

① BrowserRouter/HashRouter路由容器组件。

② Routes/Route路由配置组件。

③ Link/NavLink导航组件。

④ useNavigate/useParamsHooks API。

2)典型使用场景:

import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/products" element={<ProductList />} />
        <Route path="/products/:id" element={<ProductDetail />} />
      </Routes>
    </BrowserRouter>
  );
}

2. 状态管理方案

1)基础方案

① useState:组件内部简单状态。

② useReducer:复杂局部状态逻辑。

③ Context API:跨组件共享状态。

2)示例(Context + useReducer):

const ThemeContext = createContext();

function App() {
  const [theme, dispatch] = useReducer(themeReducer, 'light');
  
  return (
    <ThemeContext.Provider value={{ theme, dispatch }}>
      <Header />
      <MainContent />
    </ThemeContext.Provider>
  );
}

2)高级方案

① Redux:最流行的全局状态管理,适用于大型应用。

• 核心概念:Store、Action、Reducer。

• 现代工具:Redux Toolkit 简化配置。

② Zustand:轻量级状态管理,API 更简洁。

③ MobX:响应式状态管理,适合复杂交互应用。

3. 数据获取方案

1)原生方案

useEffect(() => {
  const fetchData = async () => {
    try {
      const response = await fetch('api/data');
      const data = await response.json();
      setData(data);
    } catch (error) {
      setError(error);
    }
  };
  
  fetchData();
}, []);

2)高级库

① TanStack Query (React Query)

• 自动缓存、重试、轮询。

• 内置请求状态管理。

• 示例:

const { data, isLoading, error } = useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
});

② SWR

• 轻量级数据获取。

• 支持重新验证、聚焦时刷新。

4. 样式解决方案

方案 特点 适用场景
CSS Modules 局部作用域CSS 需要隔离样式的组件
Styled-***ponents CSS-in-JS 动态样式、主题系统
Emotion 高性能CSS-in-JS 复杂样式需求
Tailwind CSS 实用类优先 快速原型开发

示例对比:

// CSS Modules
import styles from './Button.module.css';
<button className={styles.primary} />

// Styled-***ponents
const Button = styled.button`
  background: ${props => props.primary ? 'blue' : 'gray'};
`;
<Button primary />

// Tailwind
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" />

5. 构建工具与框架

1)开发工具

① Create React App (CRA)

• 官方脚手架。

• 零配置起步。

• 适合学习和小型项目。

② Vite

• 极速启动。

• 原生ES模块支持。

• 适合现代浏览器开发。

2)生产框架 Next.js

① 服务端渲染(SSR)。

② 静态生成(SSG)。

③ 文件系统路由。

④ API路由。

⑤ 示例:

// pages/index.js
export default function Home({ posts }) {
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>{post.title}</article>
      ))}
    </div>
  );
}

export async function getStaticProps() {
  const res = await fetch('https://.../posts');
  const posts = await res.json();
  return { props: { posts } };
}

五、总结

要掌握 React,我们需要:

1)理解其思想:声明式、组件化、单向数据流。

2)熟练运用基础:JSX、函数组件、Props、State、事件处理。

3)精通 Hooks:特别是 useStateuseEffectuseContext,并理解 useMemo/useCallback 等优化 Hooks 的使用场景。

4)掌握关键模式:状态提升、受控组件、组合。

5)了解高级特性:代码分割、错误边界等,并在需要时使用。

这份梳理涵盖了 React 最核心和常用的知识点。建议通过实际项目来巩固这些概念,从简单的组件开始,逐步构建更复杂的应用。

转载请说明出处内容投诉
CSS教程网 » 【Web前端】React核心知识点梳理

发表评论

欢迎 访客 发表评论

一个令你着迷的主题!

查看演示 官网购买