了解 React
- react 是什么?
- react 是一个视图层框架,类似 MVC 中的 V
- 视图
- 将后端的数据高效的渲染到视图
- 将用户输入的信息高效的展示在界面
 
 
- react 具有组件系统
- 组件是一个独立的聚合体,复用性高,比如: 车上的零件坏了
 
- react 是单向数据流
 
- react 特点
- 虚拟 DOM
- DIFF 算法【16 版本之后更新为 Filber 算法】
- 组件系统化
- 单向数据流
- jsx
- 函数式编程
- 插件化编程
- 一切皆组件
 
react 脚手架使用
- create-react-app| 12
 
 | $ cnpm i create-react-app -g    $ create-react-app
 
 |  
 
- dva
- umi
类组件/函数组件
- 在 src 目录下创建 index.js 入口文件和 App.js 组件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | 
 import React from "react";
 
 
 class App extends React.Component {
 render() {
 return <div>这是React类组件写法</div>;
 }
 }
 
 
 
 
 
 
 
 
 
 
 export default App;
 
 | 
- 在 index.js 中引入并使用
| 12
 3
 4
 5
 6
 7
 
 | 
 import ReactDOM from "react-dom";
 import App from "./App";
 
 
 ReactDOM.render(<App />, document.querySelector("#root"));
 
 | 
组件嵌套
入口文件 index.js/Farther.js/Son.js
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import React from "react";
 import Son from "./Son";
 
 class Farther extends Component {
 render() {
 return (
 <div>
 Far
 <Son />
 </div>
 );
 }
 }
 
 export default Farther;
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | import React from "react";
 
 class Son extends React.Component {
 render() {
 return <div>Son</div>;
 }
 }
 
 export default Son;
 
 | 
| 12
 3
 4
 5
 
 | import ReactDOM from "react-dom";
 import Farther from "./Farther";
 
 ReactDOM.render(<Farther />, document.querySelector("#root"));
 
 | 
组件组合
this.props.children 可以类似插槽的功能,用于组合,接下来每个 index.js 入口文件都不写了
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 
 | import React, { Component } from 'react'
 class Todolist extends Component {
 render() {
 return (
 <div>
 <h1>Todolist</h1>
 { this.props.children }
 </div>
 )
 }
 }
 
 class Tab extends React.Component{
 render () {
 return <div>
 <h1> tab </h1>
 </div>
 }
 }
 class Content extends React.Component{
 render () {
 return <div>
 <h1> content </h1>
 </div>
 }
 }
 class TabBar extends React.Component{
 render () {
 return <div>
 <h1> TabBar </h1>
 </div>
 }
 }
 
 class App extends Component {
 render() {
 return (
 <div>
 <TodoList>
 <Tab/>
 <Content/>
 <TabBar>
 </TodoList>
 </div>
 )
 }
 }
 
 export default App
 
 | 
react 组件的样式
全局样式
- 写法 import ‘xxx.css/scss/less’
- 渲染到界面时类名就是自定义类名
局部样式
- xxx.module.css 局部样式
- import styles from ‘xxx.module.css’
cra 使用 sass
- 需要安装两个插件 node-sass sass-loader
| 1
 | $ yarn add node-sass sass-loader -D
 | 
cra 使用 less
- 找到 sass 配置 config 并拷贝
- 安装 less 和 less-loader
| 1
 | $ yarn add less less-loader -D
 | 
行内样式
在标签中加 style 属性 并用双括号
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | <pstyle={{
 width: "100px",
 height: "100px",
 background: "red",
 }}
 ></p>
 
 
 
 
 
 
 | 
类名的操作/classnames 插件
| 1
 | $ yarn add classnames -D
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | import cl from "classnames";
 <p
 className={cl({
 a: true,
 b: true,
 c: false,
 })}
 ></p>;
 
 | 
样式组件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | import React, { Component } from "react";
 
 import styled from "styled-components";
 
 
 const Container = styled.div`
 width: 100px;
 height: 100px;
 background: ${(props) => props.color || "red"};
 `;
 
 export default class App extends Component {
 color = "pink";
 render() {
 return (
 <div>
 <Container />
 <Container color={this.color} />
 </div>
 );
 }
 }
 
 | 
react 事件
合成事件
案例:点击按钮弹出框
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import React, { Component } from "react";
 export default class App extends Component {
 
 fn = () => {
 alert("111");
 };
 
 render() {
 
 return (
 <div>
 <button onClick={this.fn}>点击</button>
 </div>
 );
 }
 }
 
 | 
事件对象
案例:回车时弹出 input 的 value 值
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | import React, { Component } from "react";
 export default class App extends Component {
 getVal = (e) => {
 if (e.keyCode == 13) {
 alert(e.target.value);
 }
 };
 
 render() {
 return (
 <div>
 <input type="text" placeholder="请输入..." onKeyDown={this.getVal} />
 </div>
 );
 }
 }
 
 | 
事件传参
事件传参时需要加一层箭头函数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | import React, { Component } from "react";
 export default class App extends Component {
 fn = (n) => {
 alert(n);
 };
 
 render() {
 return (
 <div>
 <button
 onClick={() => {
 this.fn(10);
 }}
 >
 点击
 </button>
 </div>
 );
 }
 }
 
 | 
this 绑定问题
问题: 普通函数中的 this 丢失, 是普通函数不是箭头函数
原因: 引文事件源这个 button 是虚拟 DOM
解决: bind
- 调用时绑定 bind this.fn.bind(this)
- 在构造函数中绑定 this constructor () { super(); this.fn = this.fn.bind(this) }
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | import React, { Component } from "react";
 export default class App extends Component {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 fn() {
 console.log("普通函数this", this);
 }
 
 render() {
 return (
 <div>
 <button onClick={this.fn.bind(this)}>按钮</button>
 </div>
 );
 }
 }
 
 | 
原生事件
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | import React, { Component } from "react";
 export default class App extends Component {
 componentDidMount() {
 
 
 const btn = document.querySelector("button");
 btn.onclick = function () {
 alert("原生事件");
 };
 }
 
 render() {
 return (
 <div>
 <button>按钮</button>
 </div>
 );
 }
 }
 
 | 
react 组件数据形式
props-外部传入
- 父组件通过属性绑定的形式绑定数据给子组件
- 子组件获取属性用{this.props.xxx}
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | import React, { Component } from "react";
 class Hello extends Component {
 render() {
 return (
 <div>
 {}
 <p> {this.props.name} </p>
 <p> {this.props.age} </p>
 </div>
 );
 }
 }
 
 export default class App extends Component {
 render() {
 return (
 <div>
 {}
 <Hello name="yyc" age={18} />
 </div>
 );
 }
 }
 
 | 
props-自身定义
类组件通过一个关键字 static defaultProps = {} 来定义自身属性
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | import React, { Component } from "react";
 export default class App extends Component {
 
 static defaultProps = {
 color: "pink",
 };
 render() {
 const { color } = this.props;
 return (
 <div>
 <p> {color} </p>
 </div>
 );
 }
 }
 
 | 
props-属性校验
- 需要第三方依赖包 prop-types
| 1
 | $ yarn add prop-types -S
 | 
- 代码部分
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 
 | import React, { Component } from "react";import PropTypes from "prop-types";
 
 class Hello extends Component {
 render() {
 const { name, age } = this.props;
 return (
 <div>
 <p> {name} </p>
 <p> {age} </p>
 </div>
 );
 }
 }
 
 Hello.propTypes = {
 
 name: PropTypes.string,
 age: PropTypes.number,
 addProp(props, propName, componentName) {
 
 
 
 
 if (props.age < 18) {
 alert(" 未成年 ");
 }
 },
 };
 
 export default class App extends Component {
 render() {
 return (
 <div>
 <Hello name="yyc" age={17} />
 </div>
 );
 }
 }
 
 | 
state-两种定义形式
- 构造函数定义
- class 直接定义
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | import React, { Component } from "react";
 export default class App extends Component {
 
 
 
 
 
 
 
 
 
 state = {
 name: "yyc",
 };
 
 render() {
 const { name } = this.state;
 return (
 <div>
 <p> {name} </p>
 </div>
 );
 }
 }
 
 | 
setState-改变 state-案例
setState(()=>{},()=>{})
接收两个回调函数
第一个回调函数可以带有参数 pre,用于接收旧值
- 案例 1: 计数按钮
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | import React, { Component } from "react";
 export default class App extends Component {
 constructor() {
 super();
 this.state = {
 
 count: 1,
 };
 }
 
 add = () => {
 
 this.setState((pre) => {
 return {
 count: pre.count + 1,
 };
 });
 };
 
 render() {
 const { count } = this.state;
 return (
 <div>
 <button onClick={this.add}> + </button>
 <p> {count} </p>
 </div>
 );
 }
 }
 
 | 
- 案例 2: 修改网页 title-合成事件-异步
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 
 | import React, { Component } from "react";
 export default class App extends Component {
 constructor() {
 super();
 this.state = {
 name: "张三",
 };
 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 changeName = () => {
 this.setState(
 () => {
 return {
 name: "李四",
 };
 },
 () => {
 document.title = this.state.name;
 }
 );
 };
 
 render() {
 const { name } = this.state;
 return (
 <div>
 <button onClick={this.changeName}>改变名字</button>
 <p> {name} </p>
 </div>
 );
 }
 }
 
 | 
- 案例 3: 原生同步
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | import React, { Component } from "react";
 export default class App extends Component {
 constructor() {
 super();
 this.state = {
 name: "张三",
 };
 }
 
 componentDidMount() {
 const btn = document.querySelector("button");
 const _this = this;
 btn.onclick = function () {
 _this.setState({
 name: "李四",
 });
 document.title = _this.state.name;
 };
 }
 
 render() {
 const { name } = this.state;
 return (
 <div>
 <button onClick={this.changeName}>改变名字</button>
 <p> {name} </p>
 </div>
 );
 }
 }
 
 | 
setState()在 render()中不能使用
render 函数中不能直接调用 setState
报错: 栈溢出(死循环)
原因: render 函数本身就是用于解析 this.state 和 this.props 的,解析时开始矛盾
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | import React, { Component } from "react";
 export default class App extends Component {
 constructor() {
 super();
 this.state = {
 count: 1,
 };
 }
 render() {
 const { count } = this.state;
 
 
 
 
 return (
 <div>
 <p> {count} </p>
 </div>
 );
 }
 }
 
 | 
react-数据渲染
条件渲染
demo: 渲染一个标签, 在 react 中 {} 单花括号可以写 js 逻辑
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | import React, { Component } from "react";
 export default class App extends Component {
 state = {
 flag: true,
 };
 
 setFlag = () => {
 this.setState({
 flag: !this.state.flag,
 });
 };
 render() {
 const { flag } = this.state;
 return (
 <div>
 <button onClick={this.setFlag}>按钮</button>
 {
 
 flag && <p>你好</p>
 }
 </div>
 );
 }
 }
 
 | 
列表渲染 + 数据请求 + 反向代理
- 列表渲染使用 map 语法, 也就是原生的数组方法, 使用该方法一定要是数组。
- cra-配置文件抽离-反向代理:
- 目录路径 config/webpackDevServer.config.js
- 找到 proxy
- 书写反向代理| 12
 3
 4
 5
 6
 
 | proxy: {'/ajax': {
 target: 'https://m.maoyao.com',
 changeOrigin: true
 }
 },
 
 |  
 
 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 
 | import React, { Component } from "react";
 export default class App extends Component {
 state = {
 list: null,
 flag: false,
 };
 
 getList = () => {
 this.setState({
 flag: true,
 });
 fetch(
 "/ajax/movieOnInfoList?token=&optimus_uuid=03700780983E11EBBCE74F727D62BDE1238C6477E95F4AE98875338903338692&optimus_risk_level=71&optimus_code=10"
 )
 .then((data) => data.json())
 .then((res) => {
 this.setState({
 list: res.movieList,
 flag: false,
 });
 })
 .catch((error) => Promise.reject(error));
 };
 render() {
 const { list, flag } = this.state;
 return (
 <div>
 <button onClick={this.getList}>按钮</button>
 {
 
 flag && <div>loading...</div>
 }
 <ul>
 {
 
 list && list.map((item) => <li key={item.id}> {item.nm} </li>)
 }
 </ul>
 </div>
 );
 }
 }
 
 | 
路径别名
- 路径别名配置
- 目录路径 config/webpack.config.js
- 找到 alias c
- 书写路径别名配置| 12
 3
 4
 
 | alias: {
 'c': path.join(__dirname,'./src/components')
 }
 
 |