文章目录
- React是什么?
- [1. JSX 简介](#1. JSX 简介)
-
- [1.1 在 JSX 中嵌入表达式](#1.1 在 JSX 中嵌入表达式)
- [1.2 JSX 中指定属性](#1.2 JSX 中指定属性)
- [1.3 使用 JSX 指定子元素](#1.3 使用 JSX 指定子元素)
- [1.4 JSX 表示对象](#1.4 JSX 表示对象)
- [2. 元素渲染](#2. 元素渲染)
-
-
- [2.1 将一个元素渲染为 DOM](#2.1 将一个元素渲染为 DOM)
-
- [3. 组件 & Props](#3. 组件 & Props)
-
- [3.1 函数组件与class组件](#3.1 函数组件与class组件)
-
- [3.1.1 函数组件](#3.1.1 函数组件)
- [3.1.2 class组件](#3.1.2 class组件)
- [3.2 渲染组件 & props](#3.2 渲染组件 & props)
- [3.1 Props的只读性](#3.1 Props的只读性)
- [4. State & 生命周期](#4. State & 生命周期)
-
- [4.1 class 组件中的 state](#4.1 class 组件中的 state)
-
- [4.2 class组件中的生命周期](#4.2 class组件中的生命周期)
- [4.3 正确使用State](#4.3 正确使用State)
-
- [4.3.1 不要直接修改 State](#4.3.1 不要直接修改 State)
- [4.3.2 State 的更新可能是异步的](#4.3.2 State 的更新可能是异步的)
- [4.3.3 State 的更新会被合并](#4.3.3 State 的更新会被合并)
- [4.4 数据是向下流动的](#4.4 数据是向下流动的)
- [5. 事件处理](#5. 事件处理)
-
- [5.1 基本使用](#5.1 基本使用)
- [5.2 class组件中的this问题](#5.2 class组件中的this问题)
-
- [5.2.1 使用bind来解决this问题](#5.2.1 使用bind来解决this问题)
- [5.2.2 使用类字段来解决this问题(常用)](#5.2.2 使用类字段来解决this问题(常用))
- [5.2.3 回调中使用箭头函数解决this问题](#5.2.3 回调中使用箭头函数解决this问题)
- [5.3 向事件处理程序传递参数](#5.3 向事件处理程序传递参数)
- [6. 条件渲染](#6. 条件渲染)
-
- [6.1 `if` 语句进行条件渲染](#6.1
if
语句进行条件渲染) - [6.2 与运算符 &&](#6.2 与运算符 &&)
- [6.3 三目运算符](#6.3 三目运算符)
- [6.1 `if` 语句进行条件渲染](#6.1
- [7. 列表 & Key](#7. 列表 & Key)
-
- [7.1 基础列表组件](#7.1 基础列表组件)
- [7.2 key](#7.2 key)
- [8. 表单](#8. 表单)
-
- [8.1 受控组件](#8.1 受控组件)
- [8.2 处理多个输入](#8.2 处理多个输入)
- [9. 状态提升](#9. 状态提升)
- [10. 组合 vs 继承](#10. 组合 vs 继承)
-
- [10.1 包含关系](#10.1 包含关系)
- [11. 样式](#11. 样式)
-
- [11.1 行内样式](#11.1 行内样式)
- [11.2 class 类名](#11.2 class 类名)
React是什么?
用于构建用户界面的 JavaScript 库
1. JSX 简介
1.1 在 JSX 中嵌入表达式
声明变量 name,并包裹在大括号中
js
const name = 'world';
const element = <h1>Hello, {name}</h1>;
在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式
1.2 JSX 中指定属性
可以使用大括号,来在属性值中插入一个 JavaScript 表达式:
js
const element = <img src={user.avatarUrl}></img>;
1.3 使用 JSX 指定子元素
JSX 标签里能够包含很多子元素:
js
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
1.4 JSX 表示对象
js
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
等效于:
js
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
2. 元素渲染
2.1 将一个元素渲染为 DOM
页面根节点
html
<div id="root"></div>
将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入
js
const root = ReactDOM.createRoot(
document.getElementById('root')
);
const element = <h1>Hello, world</h1>;
root.render(element);
3. 组件 & Props
组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思
3.1 函数组件与class组件
注意:组件名称必须以大写字母开头
3.1.1 函数组件
接受任意的入参(即 "props")
js
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
3.1.2 class组件
js
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
3.2 渲染组件 & props
当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 "props"
js
const element = <Welcome name="Sara" />;
子组件(children)例子:
js
<Welcome name="react">
<span>children</span>
</Welcome>
最终props为
js
{name: 'react', children: {...}}
3.1 Props的只读性
组件无论是使用 函数声明还是通过 class 声明,都决不能修改自身的 props
纯函数:函数不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。
如:
js
function sum(a, b) {
return a + b;
}
相反,下面这个则不是纯函数
js
function withdraw(account, amount) {
account.total -= amount;
}
所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。
4. State & 生命周期
4.1 class 组件中的 state
js
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
4.2 class组件中的生命周期
componentDidMount
:方法会在组件已经被渲染到 DOM 中后运行
componentWillUnmount
:方法会在组件卸载前调用
js
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
4.3 正确使用State
4.3.1 不要直接修改 State
例如,此代码不会重新渲染组件:
js
// 错误
this.state.comment = 'Hello';
而是应该使用 setState()
:
js
// 正确
this.setState({comment: 'Hello'});
构造函数是唯一可以给 this.state
赋值的地方。
4.3.2 State 的更新可能是异步的
出于性能考虑,React 可能会把多个 setState()
调用合并成一个调用。
因为 this.props
和 this.state
可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
比如:
js
// 错误
this.setState({
counter: this.state.counter + this.props.increment,
});
解决这个问题:
可以让 setState()
接收一个函数而不是一个对象
js
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
4.3.3 State 的更新会被合并
当你调用 setState()
的时候,React 会把你提供的对象合并到当前的 state。
4.4 数据是向下流动的
5. 事件处理
5.1 基本使用
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
示例:
js
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
5.2 class组件中的this问题
先来报错案例:
说明: JSX 回调函数中的 this
,在 JavaScript 中,class 的方法默认不会绑定this
js
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'hello' };
}
handleClick() {
console.log(this) // 这里this为undefined
this.setState({ message: '你好' })
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.message}</h2>
<button onClick={this.handleClick}>点击事件</button>
</div>
);
}
}
5.2.1 使用bind来解决this问题
为了在回调中使用 this
,对this.handleClick.bind(this);这个绑定是必不可少的
js
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { message: 'hello' };
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this)
this.setState({ message: '你好' })
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.message}</h2>
<button onClick={this.handleClick}>点击事件</button>
</div>
);
}
}
5.2.2 使用类字段来解决this问题(常用)
js
class LoggingButton extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
5.2.3 回调中使用箭头函数解决this问题
js
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
5.3 向事件处理程序传递参数
js
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
6. 条件渲染
6.1 if
语句进行条件渲染
js
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
6.2 与运算符 &&
js
render() {
const count = 0;
return (
<div>
{count && <h1>Messages: {count}</h1>}
</div>
);
}
6.3 三目运算符
js
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
7. 列表 & Key
7.1 基础列表组件
使用 map
函数
js
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{
numbers.map(item => {
return <li>{item}</li>
})
}
</ul>
)
}
7.2 key
应当给数组中的每一个元素赋予一个确定的标识
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串,最好是用id
注意,最好不要用索引index作为key,有可能会导致一些问题
js
function NumberList() {
const numbers = [1, 2, 3, 4, 5];
return (
<ul>
{
numbers.map(item => {
return <li key={item.toString()}>{item}</li>
})
}
</ul>
)
}
8. 表单
8.1 受控组件
渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做"受控组件"。
js
class FormDemo extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '',
textAreaValue: '',
selectValue: '',
}
}
handleNameChange = (e) => {
this.setState({ value: e.target.value })
}
handleTextAreaChange = (e) => {
this.setState({ textAreaValue: e.target.value })
}
handleSelectChange = (e) => {
this.setState({ selectValue: e.target.value })
}
handleSubmit = () => {
alert('提交的 input:' + this.state.value)
alert('提交的 textarea:' + this.state.textAreaValue)
alert('提交的 select:' + this.state.selectValue)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input value={this.state.value} onChange={this.handleNameChange}></input>
</label>
<br />
<label>
文章:
<textarea value={this.state.textAreaValue} onChange={this.handleTextAreaChange} />
</label>
<br />
<label>
选择你喜欢的风味:
<select value={this.state.selectValue} onChange={this.handleSelectChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</label>
<br />
<input type="submit" value="提交" />
</form>
)
}
}
8.2 处理多个输入
当需要处理多个 input
元素时,我们可以给每个元素添加 name
属性,并让处理函数根据 event.target.name
的值选择要执行的操作。
js
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
参与:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
来宾人数:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
9. 状态提升
在 React 中,将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中,便可实现共享 state。这就是所谓的"状态提升"
示例:
js
// 子组件 A
class A extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
handleClick = () => {
// 这里调用父组件传过来的方法进行修改父组件的state
this.props.onGetAName('这是a传过来的')
}
render() {
return (
<div>
<h3>这是A组件</h3>
<button onClick={this.handleClick}>a按钮</button>
</div>
)
}
}
// 子组件 B
class B extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<div>
<h3>这是B组件,接收a的数据:{this.props.name}</h3>
</div>
)
}
}
// 父组件
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
aName: ''
};
}
getName = (val) => {
this.setState({ aName: val })
}
render() {
return (
<div className="App">
<A onGetAName={this.getName}></A>
<B name={this.state.aName}></B>
</div>
)
}
}
10. 组合 vs 继承
推荐使用组合而非继承来实现组件间的代码重用。
10.1 包含关系
组件使用一个特殊的 children
prop 来将他们的子组件传递到渲染结果中:
js
function FancyBorder(props) {
return (
<div className={'FancyBorder FancyBorder-' + props.color}>
{props.children}
</div>
);
}
这使得别的组件可以通过 JSX 嵌套,将任意组件作为子组件传递给它们。
js
function WelcomeDialog() {
return (
<FancyBorder color="blue">
<h1 className="Dialog-title">
Welcome
</h1>
<p className="Dialog-message">
Thank you for visiting our spacecraft!
</p>
</FancyBorder>
);
}
11. 样式
11.1 行内样式
{} 中绑定一个style对象
js
<h1 style={{ color: "red" }} onClick={this.click}>
hello
</h1>
推荐:
js
const style = {
fontSize: "50px",
color: 'red'
};
function App() {
return (
<div>
<h1 style={style}>这是 App</h1>
<Hello />
</div>
);
}
11.2 class 类名
- 注意:这里绑定class要用 className
.css
css
.title {
color: red;
}
App.js
js
<h1 className="title" onClick={this.click}>
hello
</h1>