React 快速入门
概述
本文主要介绍 React 基础知识,包括创建第一个 React 应用、组件的概念和使用、JSX 语法、事件响应、界面更新、组件与 Props、状态管理、表单处理、条件渲染和列表渲染等内容。
HelloWorld
DEMO: react-journey/01/helloworld.html
function MyApp() {
return <h1>Hello, world!</h1>;
}
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<MyApp />);
创建和嵌套组件
React 组件:
- React 程序由组件组成
- 一个组件是 UI 的一部分,拥有自己的逻辑和外观
- 组件可以小到一个按钮,也可以大到一个页面
- React 组件是返回 JSX 的 JavaScript 函数
DEMO: react-journey/01/my-button.html
function MyButton() {
return <button>Click me</button>;
}
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
)
}
说明:
- React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母,如:
MyButton
、MyApp
export default
关键字指定了文件中的主要组件
使用 JSX 写标签
什么是 JSX?
JSX 可以理解为是一种特殊的语法糖,可以让你在 JS 代码中直接写 HTML 一样的代码:
DEMO: react-journey/01/jsx.html
// 这是 JSX 写法
function Welcome() {
const name = "谢小沛";
return (
<>
<h1>你好!</h1>
<p>{name}</p>
</>
);
}
DEMO: react-journey/01/no-jsx.html
// 这是不使用 JSX 的写法
function Welcome() {
const name = "谢小沛";
return React.createElement(
'div',
null,
React.createElement('h1', null, '你好!'),
React.createElement('p', null, name)
);
}
JSX 特点:
- 更直观:像 HTML 一样写界面,代码结构更清晰容易理解
- 更灵活:可以在 JSX 中嵌入 JS 表达式
- 有规则:
- 必须闭合标签
- 要有一个根标签包裹(如:
<div>...</div>
或<>...</>
) - 使用 className 而不是 class(因为 class 是 JS 关键字)
PS:工具:HTML -> JSX 在线转换器
添加标签样式
DEMO: react-journey/01/add-style.html
function Square() {
return <div className="square"></div>;
}
function MyApp() {
return (
<div>
<Square />
</div>
);
}
.square {
border: 3px solid #ccc;
width: 100px;
height: 100px;
display: inline-block;
}
显示数据
DEMO: react-journey/01/show-data.html
const user = {
name: '谢小沛',
occupation: 'Front-end Developer',
};
const Profile = () => {
return (
<>
<p>姓名:{user.name} </p>
<p>职业:{user.occupation}</p>
</>
);
};
function MyApp() {
return (
<div>
<Profile />
</div>
);
}
条件渲染
DEMO: react-journey/01/condition.html
条件渲染 if
:
const isShow = true;
const Content = () => {
let content;
if (isShow) {
content = <div>Blow up!</div>;
} else {
content = <div>Nothing happened.</div>;
}
return content;
};
条件渲染 ?
(三元表达式):
content = isShow ? <div>Blow up!</div> : <div>Nothing happened.</div>;
当你不需要 else
分支时,你还可以使用 逻辑 &&
语法:
content = isShow && <div>Blow up with `&&` !</div>;
列表渲染
渲染列表:可以使用 for
循环和数组的 map()
函数 来渲染组件列表:
DEMO: react-journey/01/loop.html
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
const ProductList = () => {
// 写法 1:使用 for...of 循环遍历 products
const listItems = [];
for (const product of products) {
listItems.push(<li key={product.id}>{product.title}</li>);
}
// 写法 2:map 方法会返回一个新数组,非常适合 React 的列表渲染
// const listItems = products.map((product) => <li key={product.id}>{product.title}</li>);
return <ul>{listItems}</ul>;
};
响应事件
通过在组件中声明事件处理函数来响应事件:
DEMO: react-journey/02/event.html
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return <button onClick={handleClick}>点我</button>;
}
function MyApp() {
return <MyButton />;
}
注意:只需传递函数给事件,不需要调用函数!
更新界面
如果需要组件“记住信息”,则需要引入 state
:
DEMO: react-journey/02/state.html
const { useState } = React;
function MyApp() {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<MyApp />);
useState
说明:
- 从
useState()
中可以获得两样东西:当前的 state(count
),以及用于更新它的函数 setState(setCount
) - 第一次在
useState()
传的值是默认值,如:本例中count
的初始值为 0 - 如果多次渲染同一个组件,则每个组件都有拥有自己的 state,互不影响
使用 Hook
什么是 Hook?
- 以 use 开头的函数被称为 Hook
useState
是 React 提供的一个内置 Hook,还有 其他内置的 Hook- 可以组合现有的 Hook 来创建自己的 Hook
- Hook 只能在组件顶层调用
如何理解“Hook 只能在组件顶层调用?”
- “顶层”指的是组件的函数体最外层,也就是在组件的函数定义中,不在任何条件语句、循环、嵌套函数或其他代码块内部
- Hook 必须在顶层使用,以确保 React 能够正确跟踪和管理 Hook 的状态
- 如果需要条件逻辑,可以将条件判断放在 Hook 内部,而不是在 Hook 的调用上
// ✅ 正确示例
function MyComponent() {
const [count, setCount] = useState(0); // 顶层
useEffect(() => {
console.log("Component mounted");
}, []); // 顶层
return <div>{count}</div>;
}
// ❌ 错误示例
function MyComponent() {
if (someCondition) {
const [count, setCount] = useState(0); // 错误:在条件语句中
}
useEffect(() => {
const [name, setName] = useState(""); // 错误:在嵌套函数中
}, []);
return <div>{count}</div>;
}
Q:那么,如果按错误示例去写,页面会有什么报错信息吗? A:会,信息如下:
组件间共享数据
前面说到,state 放在 MyBtn 组件(子组件)里面,即使多次渲染同一个组件,仍互不影响
但是很多情况下,你需要不同组件共享同一个数据
这时候,你就需要把 state 提升到父组件(状态提升),然后把值向下传递给不同子组件(prop 传值)
DEMO: react-journey/02/shared-state.html
function MyApp() {
// 状态声明
const [count, setCount] = useState(0);
// 点击方法
const handleClick = () => {
setCount(count + 1);
};
return (
<>
<MyBtn count={count} onClick={handleClick} />
<MyBtn count={count} onClick={handleClick} />
<MyBtn count={count} onClick={handleClick} />
</>
);
}
// 传入在父组件定义的状态变量及点击方法到子组件
function MyBtn({ count, onClick }) {
return (
<div>
<h1>Count: {count}</h1>
<button onClick={onClick}>Increment</button>
</div>
);
}
资源
- xiezipei/react-journey // 代码仓库
参考
- 快速入门 – React 中文文档 // 官方文档