配置环境
导航:React
安装Git Bash
(仅限使用Windows的同学,使用Mac和Linux的同学无需安装)
安装Nodejs
安装create-react-app
打开Git Bash
,执行:
npm i -g create-react-app
安装VSCode
的插件
Simple React Snippets
Prettier - Code formatter
创建React App
在目标目录下打开Git Bash
,在终端中执行:
create-react-app react-app # 可以替换为其他app名称
cd react-app
npm start # 启动应用
JSX
React
中的一种语言,会被Babel编译成标准JavaScript。
ES6
使用bind()
函数绑定this
取值
在JavaScript中,函数里的this
指向的是执行时的调用者,而非定义时所在的对象。
例如:
const person = {
name: "yxc",
talk: function() {
console.log(this);
}
}
person.talk();
const talk = person.talk;
talk();
运行结果:
{name: 'yxc', talk: ƒ}
Window
bind()
函数,可以绑定this
的取值。例如:
const talk = person.talk.bind(person);
箭头函数的简写方式
const f = (x) => {
return x * x;
};
可以简写为:
const f = x => x * x;
箭头函数不重新绑定this
的取值
例如:
const person = {
talk: function() {
setTimeout(function() {
console.log(this);
}, 1000);
}
};
person.talk(); // 输出Window
const person = {
talk: function() {
setTimeout(() => {
console.log(this);
}, 1000);
}
};
person.talk(); // 输出 {talk: f}
对象的解构
例如:
const person = {
name: "yxc",
age: 18,
height: 180,
};
const {name : nm, age} = person; // nm是name的别名
数组和对象的展开
例如:
let a = [1, 2, 3];
let b = [...a]; // b是a的复制
let c = [...a, 4, 5, 6];
const a = {name: "yxc"};
const b = {age: 18};
const c = {...a, ...b, height: 180};
Named 与 Default exports
- Named Export:可以export多个,import的时候需要加大括号,名称需要匹配
- Default Export:最多export一个,import的时候不需要加大括号,可以直接定义别名
Components
创建项目
创建项目box-app
:
create-react-app box-app
cd box-app
npm start
安装bootstrap
库:
npm i bootstrap
bootstrap
的引入方式:
import 'bootstrap/dist/css/bootstrap.css';
创建Component
创建按钮
当子节点数量大于1时,可以用<div>
或<React.Fragment>
将其括起来。
内嵌表达式
JSX中使用{}
嵌入表达式。
设置属性
class -> className
- CSS属性:
background-color -> backgroundColor
,其它属性类似
数据驱动改变Style
渲染列表
- 使用map函数
- 每个元素需要具有唯一的
key
属性,用来帮助React快速找到被修改的DOM元素。
Conditional Rendering
利用逻辑表达式的短路原则。
- 与表达式中
expr1 && expr2
,当expr1
为假时返回expr1
的值,否则返回expr2
的值 - 或表达式中
expr1 || expr2
,当expr1
为真时返回expr1
的值,否则返回expr2
的值
绑定事件
- 注意妥善处理好绑定事件函数的
this
修改state
- 需要使用
this.setState()
函数 - 每次调用
this.setState()
函数后,会重新调用this.render()
函数,用来修改虚拟DOM树。React只会修改不同步的实际DOM树节点。
给事件函数添加参数
例子
index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import Box from './components/box';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<div className="container"><Box/></div>
</React.StrictMode>
)
box.jsx
import React, { Component } from 'react';
class Box extends Component {
state = {
solutions: [
{key: 10, number: 1152, title: "加工零件0", view: 20},
{key: 11, number: 1153, title: "加工零件1", view: 21},
{key: 12, number: 1154, title: "加工零件2", view: 22},
{key: 13, number: 1155, title: "加工零件3", view: 23},
{key: 14, number: 1156, title: "加工零件4", view: 24},
{key: 15, number: 1157, title: "加工零件5", view: 25},
{key: 16, number: 1158, title: "加工零件6", view: 26},
{key: 17, number: 1159, title: "加工零件7", view: 27},
{key: 18, number: 1160, title: "加工零件8", view: 28},
]
}
hundleClickDelete = (s) => {
if (this.state.solutions.length === 0) return <p>没有题解了</p>
let solutions = this.state.solutions.filter(solution => solution != s);
this.setState({
solutions: solutions
});
}
render() {
return (
<table className="table">
<thead>
<tr>
<th>#</th>
<th>标题</th>
<th>阅读</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{this.state.solutions.map(solution => (
<tr key = {solution.key}>
<td>{solution.number}</td>
<td>{solution.title}</td>
<td>{solution.view}</td>
<td><button className='btn btn-danger' onClick={() => this.hundleClickDelete(solution)}>删除</button></td>
</tr>
))}
</tbody>
</table>
);
}
}
export default Box;
组合
创建Boxes
组件
Boxes
组件中包含一系列Box
组件。
从上往下传递数据
通过this.props
属性可以从上到下传递数据。
传递子节点
通过this.props.children
属性传递子节点
从下往上调用函数
注意:每个组件的this.state
只能在组件内部修改,不能在其他组件内修改。
每个维护的数据仅能保存在一个this.state
中
- 不要直接修改
this.state
的值,因为setState
函数可能会将修改覆盖掉。
创建App组件
包含:
- 导航栏组件
Boxes
组件
注意:
- 要将多个组件共用的数据存放到最近公共祖先的
this.state
中。
无状态函数组件
- 当组件中没有用到
this.state
时,可以简写为无状态的函数组件。 - 函数的传入参数为
props
对象
组件的生命周期
Mount
周期,执行顺序:constructor() -> render() -> componentDidMount()
Update
周期,执行顺序:render() -> componentDidUpdate()
Unmount
周期,执行顺序:componentWillUnmount()
路由
Web分类
- 静态页面:页面里的数据是写死的
- 动态页面:页面里的数据是动态填充的
- 后端渲染:数据在后端填充
- 前端渲染:数据在前端填充
安装环境
- VSCODE安装插件:
Auto Import - ES6, TS, JSX, TSX
- 安装
Route
组件:npm i react-router-dom
Route组件介绍
BrowserRouter
:所有需要路由的组件,都要包裹在BrowserRouter
组件内Link
:跳转到某个链接,to
属性表示跳转到的链接Routes
:类似于C++中的switch
,匹配第一个路径Route
:路由,path
属性表示路径,element
属性表示路由到的内容
URL中传递参数
解析URL:
<Route path="/linux/:chapter_id/:section_id/" element={<Linux />} />
获取参数,类组件写法:
import React, { Component } from 'react';
import { useParams } from 'react-router-dom';
class Linux extends Component {
state = { }
render() {
console.log(this.props.params);
return <h1>Linux</h1>;
}
}
export default (props) => (
<Linux
{...props}
params={useParams()}
/>
)
函数组件写法:
import React, { Component } from 'react';
import { useParams } from 'react-router-dom';
const Linux = () => {
console.log(useParams());
return (<h1>Linux</h1>);
}
export default Linux;
Search Params传递参数
类组件写法:
import React, { Component } from 'react';
import { useSearchParams } from 'react-router-dom';
class Django extends Component {
state = {
searchParams: this.props.params[0], // 获取某个参数
setSearchParams: this.props.params[1], // 设置链接中的参数,然后重新渲染当前页面
}
handleClick = () => {
this.state.setSearchParams({
name: "abc",
age: 20,
})
}
render() {
console.log(this.state.searchParams.get('age'));
return <h1 onClick={this.handleClick}>Django</h1>;
}
}
export default (props) => (
<Django
{...props}
params={useSearchParams()}
/>
);
函数组件写法:
import React, { Component } from 'react';
import { useSearchParams } from 'react-router-dom';
const Django = () => {
let [searchParams, setSearchParams] = useSearchParams();
console.log(searchParams.get('age'));
return (<h1>Django</h1>);
}
export default Django;
重定向
使用Navigate
组件可以重定向。
<Route path="*" element={ <Navigate replace to="/404" /> } />
嵌套路由
<Route path="/web" element={<Web />}>
<Route index path="a" element={<h1>a</h1>} />
<Route index path="b" element={<h1>b</h1>} />
<Route index path="c" element={<h1>c</h1>} />
</Route>
注意:需要在父组件中添加<Outlet />
组件,用来填充子组件的内容。
Redux
redux将所有数据存储到树中,且树是唯一的。
Redux基本概念
store
:存储树结构。state
:维护的数据,一般维护成树的结构。reducer
:对state
进行更新的函数,每个state
绑定一个reducer
。传入两个参数:当前state
和action
,返回新state
。action
:一个普通对象,存储reducer
的传入参数,一般描述对state
的更新类型。dispatch
:传入一个参数action
,对整棵state
树操作一遍。
React-Redux基本概念
Provider
组件:用来包裹整个项目,其store
属性用来存储redux
的store
对象。connect(mapStateToProps, mapDispatchToProps)
函数:用来将store
与组件关联起来。mapStateToProps
:每次store
中的状态更新后调用一次,用来更新组件中的值。mapDispatchToProps
:组件创建时调用一次,用来将store
的dispatch
函数传入组件。
安装
npm i redux react-redux @reduxjs/toolkit
学习自AcWing Web应用课