React 基础与实践课程笔记
一、React简介
React 是一个用于构建用户界面的 JavaScript 库,是用js构建快速响应和大型web应用的首选方法之一,在Facebook和instagram上表现优异。React 的核心特性是组件化开发和虚拟 DOM,这使得开发人员能够轻松地创建复杂且高性能的应用程序。
二、React 基础
1. JSX
JSX 是 JavaScript 的一种扩展语法,它可以让我们在 JavaScript 代码中书写类似于 HTML 的标签结构。React 使用 JSX 来描述组件的结构和样式。
const element = <h1>Hello, world!</h1>;
2. 元素渲染
React 元素是构建应用程序的最小单位。要将 React 元素渲染到页面上,我们需要使用 ReactDOM.render() 方法。
import React from 'react';
import ReactDOM from 'react-dom';
const element = <h1>Hello, world!</h1>;
ReactDOM.render(element, document.getElementById('root'));
3. 组件与 Props
React 组件允许我们将 UI 划分为独立的、可重用的部分。组件可以是函数或者类。
// 函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 类组件
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Props 是组件的输入。我们可以通过给组件传递属性(props)来设置组件的外观和行为。注意:组件内部不应该修改 props。
function App() {
return <Welcome name="Sara" />;
}
ReactDOM.render(<App />, document.getElementById('root'));
4. State 与生命周期
State 是组件内部的状态,用于存储和管理组件的数据。State 只能在类组件中使用,但是 React 16.8 引入了 Hook,使得函数组件也可以使用 state。我们可以通过 setState() 方法来更新组件的 state。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { date: new Date() };
}
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({ date: new Date() });
}
render() {
return <div>{this.state.date.toLocaleTimeString()}</div>;
}
}
ReactDOM.render(<Clock />, document.getElementById('root'));
我们先创建了一个时钟组件,会在页面上每隔一秒钟更新当前时间。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { date: new Date() };
}
这里定义了一个 Clock 类,继承自 React.Component。在构造函数中,初始化了组件的 state,其中 date 属性被设置为当前日期时间的实例。
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000);
}
在组件挂载到 DOM 树上后,会调用 componentDidMount() 方法。这里使用 JavaScript 的 setInterval() 方法来设置一个定时器,每隔一秒钟就调用一次 tick() 方法更新组件的 state。
componentWillUnmount() {
clearInterval(this.timerID);
}
当组件要从 DOM 树中被移除时,会调用 componentWillUnmount() 方法,这里清除了之前设置的定时器。
tick() {
this.setState({ date: new Date() });
}
这里定义了 tick() 方法,它会在定时器触发时被调用,用于更新组件的 state 中的 date 属性,从而重新渲染组件。
render() {
return <div>{this.state.date.toLocaleTimeString()}</div>;
}
}
最后,在组件的 render() 方法中,返回一个 div 元素,显示当前时间的字符串,使用了 toLocaleTimeString() 方法将时间转换为本地时间字符串。
最后通过 ReactDOM.render() 方法将 Clock 组件渲染到页面上,通过 document.getElementById('root') 获取到的 DOM 元素。
5. 事件处理
React 中的事件处理方式类似于 DOM 元素的事件处理,但是有一些语法和概念上的差异。例如,React 事件使用驼峰命名,而不是小写。此外,通过 JSX 传递的事件处理函数是一个函数引用,而不是一个字符串。
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState((prevState) => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
ReactDOM.render(<Toggle />, document.getElementById('root'));
三、React 实践
1. 列表与 Keys
在 React 中,我们可以使用数组的 map() 方法来遍历列表并生成新的元素。当我们创建一个元素数组时,需要为每个元素分配一个唯一的 key 属性。key 可以帮助 React 识别哪些元素发生了变化,从而提高性能。
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>{number}</li>
);
return <ul>{listItems}</ul>;
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(<NumberList numbers={numbers} />, document.getElementById('root'));
2. 表单
React 中的表单元素与 HTML 表单元素有所不同。在 React 中,表单元素的值通常通过组件的 state 进行管理,而用户输入的数据通过事件处理函数进行处理。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<NameForm />, document.getElementById('root'));
3. 状态提升
当多个组件需要共享一些数据时,我们可以将共享状态提升到它们的最近公共祖先。这使得我们能够在组件树中同步数据。
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = { temperature: '' };
}
handleChange(e) {
this.setState({ temperature: e.target.value });
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input value={temperature} onChange={this.handleChange} />
<BoilingVerdict celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
ReactDOM.render(<Calculator />, document.getElementById('root'));
其中 Calculator 组件作为父组件,BoilingVerdict 组件作为子组件。
在这个例子中,Calculator 组件通过 props 将当前温度值传递给 BoilingVerdict 组件,BoilingVerdict 组件根据接收到的温度值来判断水是否会沸腾,并返回相应的提示信息。
4. React-Router
在单页应用中,我们需要使用路由来实现页面之间的切换。React-Router 是一个用于实现路由功能的 React 插件。
首先,需要安装 React-Router:
npm install react-router-dom
然后在项目中使用:
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</div>
</Router>
);
}
ReactDOM.render(<App />, document.getElementById('root'));