React 核心基础:函数组件、Props 传参、State 状态更新

0 阅读3分钟

一、函数组件开发规范

React 组件就是返回 JSX 的函数,命名必须大写开头:

// 函数组件:首字母大写 + 返回 JSX
function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default Welcome;

组件组成规则

规则说明
首字母大写小写会被当作原生 HTML 标签
单一根节点返回单个根(可用 Fragment <>
props 只读组件不能修改传入的 props
纯函数思想相同输入 → 相同输出,不产生副作用
// 组合使用
function App() {
  return (
    <>
      <Welcome name="React" />
      <Welcome name="Vue" />
    </>
  );
}

二、Props 传参:父传子与只读特性

2.1 基础传参

// 父组件
function App() {
  const user = { name: "张三", age: 18 };
  return <UserCard name={user.name} age={user.age} title="成员卡片" />;
}
// 子组件(解构接收)
function UserCard({ name, age, title }) {
  return (
    <div className="card">
      <h3>{title}</h3>
      <p>{name} - {age} 岁</p>
    </div>
  );
}

2.2 children:插槽内容

function Card({ children }) {
  return <div className="card">{children}</div>;
}

// 使用:标签内的内容作为 children 传入
<Card>
  <p>这是卡片内容</p>
</Card>

2.3 props 只读(单向数据流)

props 是只读的,子组件直接修改会报错(Cannot assign to read only property)。需要变化的数据由父组件用 state 管理,通过回调函数让父组件改

// 子组件:通过回调通知父组件
function Counter({ count, onIncrement }) {
  return <button onClick={onIncrement}>计数:{count}</button>;
}

// 父组件:state 变化驱动重渲染
function App() {
  const [count, setCount] = useState(0);
  return <Counter count={count} onIncrement={() => setCount(count + 1)} />;
}

三、props 默认值与类型校验

3.1 默认值(解构默认参数)

function Button({ text = "确定", type = "primary" }) {
  return <button className={`btn-${type}`}>{text}</button>;
}

3.2 PropTypes 类型校验

npm install prop-types
import PropTypes from "prop-types";

function UserCard({ name, age }) {
  return <p>{name},{age} 岁</p>;
}

// 声明类型与必填
UserCard.propTypes = {
  name: PropTypes.string.isRequired,      // 必填字符串
  age: PropTypes.number,
  tags: PropTypes.arrayOf(PropTypes.string),
  onDelete: PropTypes.func,
};

// 默认值(另一种写法)
UserCard.defaultProps = {
  age: 0,
};

提示:TypeScript 项目直接用类型注解替代 PropTypes,校验发生在编译期。


四、useState 定义状态

4.1 基本用法

import { useState } from "react";

function App() {
  const [count, setCount] = useState(0);      // 返回 [值, 更新函数]

  return (
    <div>
      <p>当前计数:{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

4.2 函数式更新(基于上一次值)

// 连续多次更新依赖旧值时,必须用函数式写法
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);   // 结果 +2,而非只加一次

异步批量更新下,setCount(count + 1) 连续调用可能只生效一次;函数式更新 (prev) => prev + 1 永远基于最新值。


五、状态不可变原则(面试重点)

5.1 核心规则:不能直接修改 state

const [user, setUser] = useState({ name: "张三", age: 18 });

// ❌ 错误:直接修改,不触发重渲染
user.age = 19;

// ✅ 正确:创建新对象替换
setUser({ ...user, age: 19 });

5.2 对象与数组的不可变更新

// 对象:展开运算符
setUser({ ...user, age: 19 });

// 数组新增
setList([...list, newItem]);

// 数组删除
setList(list.filter((item) => item.id !== id));

// 数组更新某项
setList(list.map((item) => (item.id === id ? { ...item, done: true } : item)));

5.3 为什么不可变(面试回答要点)

  1. 触发更新:React 通过引用对比判断 state 是否变化,直接修改引用不变 → 不重渲染;
  2. 可回溯:每次更新都是新对象,便于实现时间旅行调试(DevTools 撤销/重放);
  3. 性能优化:memo / useMemo 依赖引用比较,不可变更新才能命中缓存。

六、基础页面交互案例

import { useState } from "react";

export default function TodoApp() {
  const [todos, setTodos] = useState([
    { id: 1, text: "学习 React", done: false },
  ]);
  const [input, setInput] = useState("");

  const addTodo = () => {
    if (!input.trim()) return;
    setTodos([...todos, { id: Date.now(), text: input, done: false }]);  // 不可变新增
    setInput("");
  };

  const toggle = (id) =>
    setTodos(todos.map((t) => (t.id === id ? { ...t, done: !t.done } : t)));  // 不可变更新

  const remove = (id) => setTodos(todos.filter((t) => t.id !== id));          // 不可变删除

  return (
    <div>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <button onClick={addTodo}>添加</button>
      <ul>
        {todos.map((t) => (
          <li key={t.id}>
            <span
              onClick={() => toggle(t.id)}
              style={{ textDecoration: t.done ? "line-through" : "none" }}
            >
              {t.text}
            </span>
            <button onClick={() => remove(t.id)}>删除</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

七、总结

  • 组件:函数 + 大写开头 + 返回 JSX,props 只读;
  • props:父传子、children 插槽、默认参数 + PropTypes 校验;
  • stateuseState 返回 [值, 更新函数],函数式更新防闭包;
  • 不可变原则:永远创建新对象替换,不直接改原 state(面试必问);
  • 数据驱动:setState → 引用变化 → React 重渲染 → 视图更新,这就是 React 的"数据驱动视图"。