React 快速入门:掌握前端开发的核心技能
- 一、React 简介
- 1.1 React 的历史
- 1.2 React 的概念
- 1.3 React 的特点
- 1.4 React 的官网地址
- 二、开发环境搭建
- 三、React 基础
- 3.1 JSX
- 3.2 组件
- 3.3 Props
- 3.4 State
- 3.5 props 和 state 的区别
- 3.6 Hook
- 四、React 生命周期
- 五、添加样式、显示数据
- 六、条件渲染
- 七、渲染列表
- 八、响应事件
- 九、组件间共享数据
一、React 简介
React
的雏形在 Facebook
内部首次出现。由于当时 Facebook
的前端代码越来越复杂,开发团队感受到了传统的 MVC(Model-View-Controller)
框架的局限性,开始探索一种更加灵活和高效的前端开发方式。所以 React
就出现了。
1.1 React 的历史
- 2010 年 Facebook 在其 php 生态中引入了 xhp 框架,首次引入了组合式的思想,启发了后来的 React 的设计。
- 2011 年 Jordan Walke 创造了
FaxJs
,也就是后来的 React 原型。 - 2012 年在 Facebook 收购 Instagram 后,该 Faxus 项目在内部得到使用。Jordan Walke 基于
FaxJs
的经验,创造了 React。 - 2013 年 React 正式开源,在 2013 年 Jsconf 上 Jordan Walke 介绍了这款全新的框架。
- 2014 年——今天生态大爆发,各种围绕 React 的新工具/新框架开始涌现。
- 2015 年 Jordan 开始捣鼓 React Native 并发布。然后是 Dan 和 Andrew 发明 Redux。
- 2016 年,
React
成为主流。 - 2017 年,尝试解决性能问题,开始了数年的重构,引入 Fiber 架构。
- 2019 年,Sebastian 终于设计出了替代 Class 组件副作用的函数式解决方案 -
Hooks
。完美解决了副作用和业务逻辑复用的问题。 - 2022 年,
v18concurrent
特性上线。 - 2023 年 React 新文档发布。
- 2024 年1月29日,React 15.4.0正式版发布,标志着React进入了一个新的发展阶段,带来了一系列新特性和改进。这个版本不仅展示了React在性能优化方面的新进展,也体现了组件化的进一步深化。
1.2 React 的概念
React
是一个由 Facbook
开发的 JavaScript
库,用于构建用户界面。它以可重用的组件为基础,使得开发复杂的用户界面变得更加容易和高效。再 React
中, 组件是用户界面的基本构建块,它们可以接收数据、响应用户交互,以及根据数据的改变而更新。
1.3 React 的特点
- 组件化开发:将用户界面拆分为独立的组件,每个组件可以独立开发和更新。
- 高效:React 使用虚拟
DOM
来优化DOM
操作,从而提高应用程序的性能。 - 灵活:React 支持单向数据流和组件嵌套,可以方便地构建复杂地应用程序。
- 易于维护:React 的代码分离和模块化使得应用程序易于维护。
- 支持多种开发方式:React 支持函数式编程、类式编程和基于魂灵(
Hooks
)的编程方式。 - 社区活跃:React 拥有庞大的开发者社区,并持续推出新特性和更新。
1.4 React 的官网地址
React 官方地址:https://react.docschina.org/
react 中文官网地址:https://react.nodejs.cn/
二、开发环境搭建
在开始使用 React 之前,我们需要设置开发环境。首先,确保你已经安装了 Node.js
和 npm
。然后,使用以下命令创建一个新的 React 应用:
# 创建一个名为 my-app 的 react 应用
npx create-react-app my-app
# 切换到 my-app 目录下
cd my-app
# 启动当前项目
npm start
这将创建一个名为 my-app
的新目录,并启动一个开发服务器,你可以在浏览器中访问http://localhost:3000
来查看你的应用。
三、React 基础
3.1 JSX
JSX
是一种 JavaScript 的语言扩展,它允许你在 JavaScript 中编写类似 HTML 的代码。例如:
const element = <h1>Hello, World!</h1>;
3.2 组件
React 应用由多个组件组成,每个组件都有自己的状态和逻辑。组件可以小到一个按钮,也可以大到整个页面。组件可以是函数或类:
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
至此,你已经声明了Welcome
,现在把它嵌套到另一个组件中:
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<Welcome />
</div>
);
}
注意:React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母。
3.3 Props
Props
是组件的输入,它们是只读的。你可以将 props
传递给子组件:
function Welcome(props){
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
3.4 State
通常你会希望你的组件“看记住”一些信息并展示出来,比如一个按钮被点击的次数。要做到这一点,你需要在你的组件中添加 State
。
State
是组件的私有数据,它可以改变。使用 useState
Hook
来在函数组件中添加状态:
// 引入 useState
import React, { useState } from 'react';
function Counter() {
// 声明一个 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
你将从 useState
中获得两样东西:当前的 state (count
),以及用于更新它的函数(setCount
)。你可以给它们起任何名字,但按照惯例会像[something, setSomething]
这样给为它们命名。
第一次显示按钮时,count
的值为 0
,因为你把 0
传给了 useState()
。当你想改变 state 时,调用 setCount()
并将新的值传递给它。点击该按钮计数器将递增。
如果你多次渲染同一个组件,每个组件都会拥有自己的 state。
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
3.5 props 和 state 的区别
关系:
props
和state
都是组件的状态,但它们有不同的作用域和用途。- 当子组件需要传递数据给父组件时,可以使用
props
。 - 当组件需要跟组内部状态并进行相应更新时,可以使用
state
。
区别:
props
是只读的,父组件传递给子组件,不能改变。而state
是可写的,子组件可以根据用户交互或其他条件更新state
。props
是由父组件提供,而state
可以由组件自己管理。props
是为了传递数据给子组件,state
则是为了跟踪组件内部状态。
3.6 Hook
以 use
开头的函数被称为 Hook。useState
是 React 提供的一个内置 Hook。
Hook 比普通函数更为严格。你只能在你的组件(或其他 Hook )的 顶层 调用Hook。如果你想在一个条件或循环中使用 useState
,请提取一个新的组件并在组件内部使用它。
常用的 Hook:
useState
:用于在函数组件中添加状态(state)管理。useEffect
:用于在函数组件中执行副作用操作,比如订阅数据、设置定时器、手动操作 DOM 等。useRef
:用于函数组件中创建可变的引用。useContext
:用于在函数组件中使用 Context。
四、React 生命周期
React 组件有多个生命周期方法,它们在组件的不同阶段被调用。常用的生命周期方法包括:
componentDidMount
: 组件挂载后调用componentDidUpdate
: 组件更新后调用componentWillUnMount
: 组件卸载前调用
五、添加样式、显示数据
在 React 中, 你可以使用 className
来指定一个 CSS 的 class。它与 HTML 的 class
属性的工作方式相同:
import * as React from 'react';
import './index.css';
const user = {
name: '张三',
imageUrl: '/favicon.png',
imageSize: 90,
};
const HelloWorld = () => {
function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="acatar"
src={user.imageUrl}
alt={`Photo of ${user.name}`}
style={{
width: user.imageSize,
height: user.imageSize,
}}
/>
</>
);
}
return (
<>
<h1>Welcome to my app</h1>
<Profile />
</>
);
};
export default HelloWorld;
然后,你可以在一个单独的 CSS 文件中为它编写 CSS 规则:
/* In your CSS */
.avatar {
border-radius: 50%;
}
React 并没有规定你如何添加 CSS 文件。最简单的方式是使用 HTML 的 <link>
标签。
JSX 会让你把标签放到 JavaScript 中。而大括号会让你“回到”JavaScript 中,这样你就可以从你的代码中嵌入一些变量并展示给用户。user.name
会显示 张三
,你还可以将 JSX 属性“转义到 JavaScript”,但你必须使用大括号 而非 引号。className="avatar"
是将"avatar"
字符串传递给 className
,作为 CSS 的 class。但 src={user.imageUrl}
会读取 JavaScript 的 user.imageUrl
变量,然后将该值作为 src
属性传递。
在上面示例中,style={{}}
并不是一个特殊的语法,而是 style={ }
JSX 大括号内的一个普通 {}
对象。当你的样式依赖于 JavaScript 变量时,你可以使用 style
属性。
六、条件渲染
React 没有特殊的语法来编写条件语句,因此你使用的就是普通的 JavaScript 代码。例如使用if
语句根据条件引入 JSX:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
如果你喜欢更为紧凑的代码,可以使用 condition ? value1 : value2
运算发。与 if
不同的是,它工作与 JSX 内部:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
当你不需要 else
分支时,你还可以使用 逻辑&&
语法:
<div>
{isLoggedIn && <AdminPanel />}
</div>
七、渲染列表
你将依赖 JavaScript 的特性,例如 for
循环和 array 的 map()
函数来渲染组件列表。
假设你有一个产品数组:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
在你的组件中,使用 map()
函数将这个数组转换为 <li>
标签构成的列表:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
注意,
<li>
有一个key
属性。对于列表中的每一个元素,你都应该传递一个字符串或者数字给key
,用于在其他兄弟节点中唯一标识该元素。通常 key 来自你的数据,比如数据库中的 ID。如果你在后续插入、删除或重新排序这些项目, React 将依靠你提供的 key 来思考发生了什么。
八、响应事件
你可以通过在组件中声明 **事件处理函数 ** 来响应事件:
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
注意,onClick={handleClick}
的结尾没有小括号!不要 **调用 **事件处理函数:你只需 把函数传递给事件 即可。当用户点击按钮时 React 会调用你传递的事件处理函数。
九、组件间共享数据
在前面的示例中,每个 MyButton
都有自己独立的 count
,当每个按钮被点击时,只有被点击按钮的count
才会发生改变:
然而,你经常需要组件 共享数据并一起更新。
为了使得 MyButton
组件显示相同的 count
并一起更新,你需要将各个按钮的 state “向上”移动到最接近包含所有按钮的组件之中。
在这个示例中,它是 MyApp
:
此刻,当你点击任何一个按钮时,MyApp
中的 count
都将改变,同时会改变 MyButton
中的两个count。
首先,将 MyButton
的 state 上移到 MyApp
中:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... we're moving code from here ...
}
接着,将 MyApp
中的点击事件处理函数以及** state 一同向下传递到** 每个 MyButton
中。你可以使用 JSX 的大括号向 MyButton
传递信息。就像之前向 <img>
等内置标签所做的那样:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
使用这种方式传递的信息被称作 prop
。此时 MyApp
组件包含了 count
state 以及 handleClick
事件处理函数,并将它们作为 **prop 传递给 **了每个按钮。
最后,改变 MyButton
以 **读取 **从父组件传递来的 prop:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
当你点击按钮时,onClick
处理程序会启动。每个按钮的 onClick
prop 会被设置为 MyApp
内的 handleClick
函数,所以函数内的代码会被执行。该代码会调用 setCount(count + 1)
,使得 state 变量 count
递增。新的 count
值会被作为 prop 传递给每个按钮,因此它们每次展示的都是最新的值。这种成为“
状态提升”。通过向上移动 state,我们实现了在组件间共享它。