目录
一、React概述
React 是一个流行的 JavaScript 库,它专注于用户界面的构建。它的主要特点包括:
1.组件化架构:React 使用组件来构建 UI,每个组件都是独立的,可以重复使用,这有助于代码的模块化和项目的可维护性。
2.虚拟 DOM:React 维护一个内存中的虚拟 DOM 树,只有在真正需要时才更新实际的 DOM,这提高了更新效率和性能。
3.声明式 API:开发者通过描述 UI 应该是什么样子来创建组件,React 负责实际的渲染工作,这使得代码更易理解和编写。
4.单向数据流:数据在 React 组件中从上而下流动,这有助于管理组件之间的状态和避免不必要的数据更新。
二、搭建React环境
例如创建一个名为 react-project 的项目
npx create-react-app react-project
进入项目后使用下面命令,启动项目
npm start
三、React语法
3.1 JSX:
- JSX 是 JavaScript 的一个语法扩展,它看起来很像 XML 或 HTML。
- React 使用 JSX 来描述 UI 应该呈现出什么样子。
- 使用 JSX 可以更直观地创建 React 元素,它最终会被编译成普通的 JavaScript 代码。
示例:
import React from 'react';
// 定义一个名为Greeting的React函数组件
const Greeting = (props) => {
return (
<div className="greeting-container">
<h1>{props.name}</h1>
<p>Welcome to our website, {props.name}!</p>
</div>
);
};
// 定义一个名为App的React函数组件
const App = () => {
return (
<div className="app">
<Greeting name="John" />
<Greeting name="Jane" />
</div>
);
};
// 导出App组件,以便在其他文件中使用
export default App;
3.2 组件:
- React 组件是 React 应用的基本构建块。
- 组件可以拥有自己的状态和属性,并且可以传递数据给其他组件。
- 组件可以通过函数或类来定义。
示例:
import React, { Component } from 'react';
// 函数组件
function FunctionalButton({ onClick, text }) {
return <button onClick={onClick}>{text}</button>;
}
// 类组件
class ClassCounter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<FunctionalButton onClick={this.increment} text="Increment Count" />
</div>
);
}
}
// App 组件
function App() {
return (
<div>
<h1>React Components Example</h1>
<ClassCounter />
</div>
);
}
export default App;
3.3 状态(State):
- 状态是组件内部保存动态数据的地方。
- 状态可以用来保存例如用户输入、应用程序的数据等。
- 状态是通过 this.state(类组件)或 useState(函数组件)来定义的。
示例:
import React, { Component } from 'react';
import { useState } from 'react';
// 类组件示例
class ClassComponent extends Component {
constructor(props) {
super(props);
this.state = { text: 'Hello from ClassComponent' };
}
render() {
return (
<div>
<p>{this.state.text}</p>
<button onClick={() => this.setState({ text: 'Updated Text' })}>
Update Text
</button>
</div>
);
}
}
// 函数组件示例
function FunctionalComponent() {
const [text, setText] = useState('Hello from FunctionalComponent');
return (
<div>
<p>{text}</p>
<button onClick={() => setText('Updated Text')}>
Update Text
</button>
</div>
);
}
// App 组件,结合了类组件和函数组件
function App() {
return (
<div>
<h1>React State Example</h1>
<ClassComponent />
<FunctionalComponent />
</div>
);
}
export default App;
3.4 属性(Props):
- 属性是组件从父组件接收的数据。
- 它们是只读的,用于传递数据给子组件。
- 属性是通过 this.props(类组件)或 props(函数组件)来访问的。
示例:
import React, { Component } from 'react';
// 函数组件接收props
function FunctionalChild({ name, age }) {
return (
<div>
<h2>Functional Child Component</h2>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
}
// 类组件接收props
class ClassChild extends Component {
render() {
const { name, age } = this.props;
return (
<div>
<h2>Class Child Component</h2>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
}
}
// App 组件作为父组件
function App() {
return (
<div>
<h1>Passing Props Example</h1>
<FunctionalChild name="Alice" age={25} />
<ClassChild name="Bob" age={30} />
</div>
);
}
export default App;
3.5 生命周期方法:
- 生命周期方法是 React 组件在它的生命周期中特定时间点会自动调用的方法。
- 例如,componentDidMount 在组件挂载后被调用,componentDidUpdate 在组件更新后被调用。
常见的生命周期方法及其描述:
-
getDerivedStateFromProps: 在创建组件和接收新的props时被调用。它应返回一个对象来更新状态,或者返回null以表示不需要任何更新。
-
componentDidMount: 组件挂载后立即调用。通常在这里执行AJAX请求、订阅事件或执行其他初始化操作。
-
shouldComponentUpdate: 在组件接收到新的props或state时调用,返回一个布尔值来确定是否更新组件。默认返回true,但可以通过此方法来避免不必要的渲染。
-
render: 渲染组件。这是唯一一个必须由用户定义的生命周期方法。
-
getSnapshotBeforeUpdate: 在渲染新的props或state之后,但在浏览器绘制之前调用。它使组件能在可能发生的DOM更改之前从DOM捕获一些信息。返回的任何值都将作为第三个参数传递给componentDidUpdate。
-
componentDidUpdate: 在更新后立即调用。这是执行DOM操作或网络请求的好地方。
-
componentDidCatch: 在后代组件抛出错误后被调用。它可以用于记录错误,并显示回退UI。
-
componentWillUnmount: 在组件卸载及销毁之前直接调用。用于执行任何必要的清理任务,如取消网络请求、清除定时器或取消事件监听器。
示例:
import React, { Component, useEffect, useState } from 'react';
// 使用类组件的生命周期方法
class LifecycleComponent extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
static getDerivedStateFromProps(props, state) {
if (props.initialCount !== state.count) {
return { count: props.initialCount };
}
return null;
}
componentDidMount() {
console.log('Component mounted');
}
componentDidUpdate(prevProps, prevState) {
console.log('Component updated');
}
componentWillUnmount() {
console.log('Component is about to unmount');
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
// 使用Hooks的函数组件
function HooksComponent({ initialCount }) {
const [count, setCount] = useState(initialCount);
useEffect(() => {
// 类似于componentDidMount和componentDidUpdate
console.log('Component mounted or updated');
// 清除函数,类似于componentWillUnmount
return () => {
console.log('Cleanup function called');
};
}, [count]); // 依赖项数组,决定何时运行effect
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
// App组件,作为父组件来展示这两个组件
function App() {
return (
<div>
<h1>Lifecycle Methods and Hooks Example</h1>
<LifecycleComponent initialCount={0} />
<HooksComponent initialCount={0} />
</div>
);
}
export default App;
3.6 事件处理:
- React 组件通过 on[Event] 属性来处理事件,例如 onClick、onSubmit 等。
- 事件处理函数通常会在组件内部定义。
import React, { Component } from 'react';
class ButtonComponent extends Component {
// 构造函数中绑定事件处理函数
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
// 定义事件处理函数
handleClick() {
console.log('Button clicked!');
// 在这里可以执行其他逻辑,比如更新组件状态或调用其他函数
}
// 渲染组件
render() {
return (
<button onClick={this.handleClick}>
Click Me
</button>
);
}
}
// 函数组件也可以使用事件处理
function FunctionalButton() {
// 使用箭头函数自动绑定this
const handleClick = () => {
console.log('Functional Button clicked!');
}
return (
<button onClick={handleClick}>
Click Me in a Functional Component
</button>
);
}
// App组件,作为父组件来展示ButtonComponent和FunctionalButton
function App() {
return (
<div>
<h1>Event Handling Example</h1>
<ButtonComponent />
<FunctionalButton />
</div>
);
}
export default App;
3.7 条件渲染:
- React 常用的条件渲染包括 if 语句和条件运算符(? :)。
- 例如,{condition ? 'True' : 'False'} 可以用来根据条件渲染不同的内容。
示例:
import React, { useState } from 'react';
// App 组件
function App() {
// 使用 useState 钩子来管理登录状态
const [isLoggedIn, setIsLoggedIn] = useState(false);
// 登录处理函数
const handleLogin = () => {
setIsLoggedIn(true);
};
// 注销处理函数
const handleLogout = () => {
setIsLoggedIn(false);
};
// 根据登录状态渲染不同的提示信息和按钮
const renderStatusAndButton = () => {
if (isLoggedIn) {
return (
<>
<p>用户已登录。</p>
<button onClick={handleLogout}>注销</button>
</>
);
} else {
return (
<>
<p>用户未登录。</p>
<button onClick={handleLogin}>登录</button>
</>
);
}
};
return (
<div>
{renderStatusAndButton()}
</div>
);
}
// 导出 App 组件
export default App;
3.8 列表和键:
- React 用于渲染列表的数据结构时,每个列表项都应该有一个独特的 key 属性。
- key 帮助 React 识别哪些项被改变、添加或删除。
示例:
import React, { useState } from 'react';
// 假设我们有一个待办事项列表
const initialTodos = [
{ id: 1, text: 'Learn React' },
{ id: 2, text: 'Build an app' },
{ id: 3, text: 'Deploy the app' },
];
// TodoList 组件,接收一个 todos 数组作为 props
function TodoList({ todos }) {
return (
<ul>
{/* 遍历 todos 数组,为每个待办事项创建一个 TodoItem 组件 */}
{todos.map(todo => (
<li key={todo.id}>
{/* 显示待办事项的文本 */}
{todo.text}
</li>
))}
</ul>
);
}
// TodoItem 组件,接收一个 todo 对象作为 props
function TodoItem({ todo }) {
return <>{todo.text}</>;
}
// App 组件,包含 TodoList
function App() {
const [todos, setTodos] = useState(initialTodos);
// 添加一个新的待办事项
const addTodo = () => {
const nextId = todos.length + 1;
setTodos([...todos, { id: nextId, text: `Todo ${nextId}` }]);
};
return (
<div>
<h1>My Todo List</h1>
<TodoList todos={todos} />
<button onClick={addTodo}>Add Todo</button>
</div>
);
}
// 导出 App 组件
export default App;
3.9 组件嵌套:
- 组件可以被嵌套使用,父组件可以包含子组件。
- 子组件可以通过调用父组件的 props 来接收数据。
import React from 'react';
// 子组件:Greeting,接收一个名为name的prop
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// 父组件:App,它包含了Greeting子组件
function App() {
// 在父组件中定义一些数据
const parentName = 'Parent Component';
const childName = 'Child Component';
// 将数据作为props传递给子组件
return (
<div>
<h2>This is the {parentName}.</h2>
<Greeting name={childName} /> {/* 将childName传递给Greeting组件 */}
</div>
);
}
// 导出App组件
export default App;
3.10 Hooks:
- Hooks 是 React 16.8 引入的新特性,它允许在不编写类的情况下使用状态和其他 React 特性。
- 例如,useState 是一个允许你在函数组件中添加状态的 Hook,useEffect 是一个允许你在函数组件中执行副作用的 Hook。
示例:
import React, { useState, useEffect } from 'react';
// App 组件
function App() {
// 使用 useState Hook 来添加状态
const [count, setCount] = useState(0); // 初始化 count 状态为 0
// 使用 useEffect Hook 来执行副作用,例如更新 DOM
useEffect(() => {
// 这个函数会在组件挂载后和 count 状态更新后执行
document.title = `You clicked ${count} times`;
}, [count]); // 依赖数组,仅当 count 更改时触发副作用
// 返回一个 JSX 元素,包含按钮和计数值
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
// 导出 App 组件
export default App;