跳到主要内容

Props 和 State

本章节将介绍 React 中两个核心概念:props 和 state。

props

props 是组件的输入参数,用于从父组件向子组件传递数据。

接收 props

function Welcome({ name, age }) {
return (
<div>
<h1>你好,{name}</h1>
<p>你今年 {age} 岁了</p>
</div>
);
}

使用 props

function App() {
return (
<div>
<Welcome name="张三" age={20} />
<Welcome name="李四" age={25} />
</div>
);
}

props 的类型检查

安装 PropTypes:

npm install prop-types

使用 PropTypes:

import PropTypes from "prop-types";

function UserCard({ name, age, email }) {
return (
<div>
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}

UserCard.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
email: PropTypes.string
};

UserCard.defaultProps = {
age: 0,
email: ""
};

使用 TypeScript(可选)

interface UserProps {
name: string;
age?: number;
email?: string;
}

function UserCard({ name, age = 0, email = "" }: UserProps) {
return (
<div>
<h2>{name}</h2>
<p>年龄: {age}</p>
<p>邮箱: {email}</p>
</div>
);
}

state

state 是组件内部的状态数据,用于存储组件的动态数据。

useState Hook

import { useState } from "react";

function Counter() {
const [count, setCount] = useState(0);

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

useState 返回一个数组:

  • 第一个元素:当前状态值
  • 第二个元素:更新状态的函数

多个 state

function UserForm() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [age, setAge] = useState(0);

return (
<form>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="姓名"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="邮箱"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(parseInt(e.target.value))}
placeholder="年龄"
/>
</form>
);
}

复杂 state

function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, text: "学习 React", done: false },
{ id: 2, text: "做练习", done: true }
]);

const addTodo = (text) => {
setTodos([
...todos,
{ id: Date.now(), text, done: false }
]);
};

const toggleTodo = (id) => {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
);
};

return (
<div>
<ul>
{todos.map((todo) => (
<li
key={todo.id}
onClick={() => toggleTodo(todo.id)}
style={{
textDecoration: todo.done ? "line-through" : "none"
}}
>
{todo.text}
</li>
))}
</ul>
</div>
);
}

状态更新是异步的

React 可能会批量更新状态:

function Example() {
const [count, setCount] = useState(0);

// 错误:count 不会立即更新
const handleClick = () => {
setCount(count + 1);
console.log(count); // 可能是旧值
};

// 正确:使用函数形式
const handleClick = () => {
setCount((prevCount) => prevCount + 1);
};

// 连续更新
const handleClick = () => {
setCount((prev) => prev + 1);
setCount((prev) => prev + 1);
// 结果是 +2
};

return <button onClick={handleClick}>{count}</button>;
}

useState 的初始值

// 简单值
const [count, setCount] = useState(0);

// 函数(只执行一次)
const [todos, setTodos] = useState(() => {
// 从 localStorage 读取
const saved = localStorage.getItem("todos");
return saved ? JSON.parse(saved) : [];
});

// 避免的问题
const [items, setItems] = useState(expensiveCompute()); // 每次渲染都执行
const [items, setItems] = useState(() => expensiveCompute()); // 只执行一次

props vs state

特性propsstate
来自父组件
组件内部管理
可修改❌(只读)
引起组件重新渲染

实际示例:计数器

function Counter() {
const [count, setCount] = useState(0);
const [step, setStep] = useState(1);

const increment = () => {
setCount(count + step);
};

const decrement = () => {
setCount(count - step);
};

const reset = () => {
setCount(0);
};

const changeStep = (newStep) => {
setStep(newStep);
};

return (
<div>
<h1>计数器</h1>
<p>当前值: {count}</p>
<p>步长: {step}</p>
<button onClick={increment}>+{step}</button>
<button onClick={decrement}>-{step}</button>
<button onClick={reset}>重置</button>

<div>
<button onClick={() => changeStep(1)}>步长 1</button>
<button onClick={() => changeStep(5)}>步长 5</button>
<button onClick={() => changeStep(10)}>步长 10</button>
</div>
</div>
);
}

小结

本章我们学习了:

  1. props 的概念和使用
  2. props 的类型检查
  3. state 的概念和使用
  4. useState Hook 的用法
  5. 多个 state 和复杂 state
  6. props 和 state 的区别

练习

  1. 创建一个显示当前时间的时钟组件
  2. 创建一个待办事项列表,支持添加、删除、标记完成
  3. 创建一个表单组件,包含姓名、邮箱、密码字段
  4. 创建一个评分组件,点击星标进行评分