跳到主要内容

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 标签则必须是小写字母,如:MyButtonMyApp
  • 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>;
};

PS:for...of 使用说明

响应事件

通过在组件中声明事件处理函数来响应事件:

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>
);
}

资源

参考