React基础学习

React学习

01 -《yarn 包管理器》

一、包管理器

二、安装配置 yarn

1、全局安装 yarn
css 复制代码
npm i -g yarn
2、查看版本号
复制代码
yarn -v
3、配置镜像地址

将原本的下载地址,更换为国内的地址:

arduino 复制代码
yarn config set registry https://registry.npmmirror.com

三、常用命令

1、下载局部依赖包

(1)下载局部依赖包(最新版)

csharp 复制代码
yarn add 依赖包名称

(2)下载多个局部依赖包

csharp 复制代码
yarn add 依赖包名称一 依赖包名称二

(3)下载指定版本依赖包

csharp 复制代码
yarn add 依赖包名称@版本号

(4)下载开发环境所需依赖包

开发环境,指的项目还未上线,还在开发过程中。以上3个命令,下载的都是开发和生产都需要的依赖包。

如果只在开发时需要,生产(上线)后不需要:

sql 复制代码
yarn add 依赖包名称 -D# 或yarn add 依赖包名称 --dev

(5)下载项目所有依赖包

根据项目的 package.json 文件,来下载项目所需要的所有的依赖包:

复制代码
yarn
2、下载全局依赖包
csharp 复制代码
yarn global add 依赖包名称
3、卸载依赖包

(1)卸载局部依赖包

arduino 复制代码
yarn remove 依赖包名称

(2)卸载全局依赖包

csharp 复制代码
yarn global remove 依赖包名称

02 -《搭建 React 项目》

一、搭建方式的选择

  1. React 官方脚手架:Create React App,简称 CRA,底层用的 webpack。
  2. Vite:Vue 的团队研发的,用来代替 webpack。

二、CRA 搭建 React 项目

1、创建项目
lua 复制代码
npx create-react-app react-demo

其中,react-demo 是项目名称,可自行定义。npx 临时安装,以上命令执行时会先安装 CRA 脚手架工具,然后再用工具创建项目。等到项目创建完成后,会自动删除 CRA 脚手架工具。

2、启动项目

项目的启动命令,应该在项目的 package.json 文件中,找到 scripts 配置,通常项目的启动命令在第一个。

项目的启动命令,如果用 npm:

arduino 复制代码
npm run 启动名称

特殊情况:如果启动名称叫 start,可以省略 run

如果用 yarn:

复制代码
yarn 启动名称

如果想要更换启动命令的名称,也可以在 package.json 文件中自己替换。

例如我们将 React 的 start 命令换成 dev 命令:

json 复制代码
{
    "scripts": {
        "dev": "react-scripts start"
        // ...
    },
}

更换后,React 项目的启动命令就变成了:

复制代码
yarn dev

三、删除多余文件和代码

1、删除多余文件

src 中只需要保留一下两个文件即可:

lua 复制代码
src
 |--- App.js
 |--- index.js
2、删除 index.js 中的多余代码
javascript 复制代码
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <App />
);
3、删除 App.js 中的多余代码
javascript 复制代码
function App() {
    return (
        <div>
        </div>
    );
}
export default App;

四、安装 VSCode 插件

03 -《虚拟节点》

一、虚拟节点的概念

虚拟节点,本质上是一个 JS 对象,通过 JS 对象身上的属性,来描述当前的节点,例如节点的名称、节点的属性、节点的样式...

类似:

arduino 复制代码
{
    tagName: 'div',
    children: '你好',
    // ...
}

二、创建虚拟节点

在 React 中,我们可以直接在 JS 中编写 HTML 代码:

ini 复制代码
const hello = <h1 id='hi'>你好</h1>;
console.log(hello);

通过这种方式创建的 HTML 标签,实际上就是一个虚拟节点。

而这种创建虚拟节点的方式,其底层真正的实现,是通过 React.createElement() 方法来完成的:

react 复制代码
// 真正创建虚拟节点的方式
const hello = React.createElement('h1');
console.log(hello);

04 -《React 组件》

一、组件的分类

React 组件的分为两类:

  1. 函数组件:以函数的形式来创建组件;
  2. 类组件:以类 class 的形式来创建组件;
1、函数组件

在 VSCode 中,可以通过快捷方式来创建函数组件:

(1)rfc

react 复制代码
import React from 'react'
export default function App() {
    return (
        <div>App</div>
    )
}

(2)rfce

react 复制代码
import React from 'react'
function App() {
    return (
        <div>App</div>
    )
}
export default App

(3)rafce

react 复制代码
import React from 'react'
const App = () => {
    return (
        <div>App</div>
    )
}
export default App

语法要求:

  1. 函数中必须有 return 返回值,且返回指定的内容是 HTML 标签;
  2. 函数名(组件名)首字母必须大写;
2、类 class 组件

rcc:

react 复制代码
import React, { Component } from 'react'
export default class App extends Component {
    render() {
        return (
            <div>App</div>
        )
    }
}

二、创建组件文件

  1. 在 React 组件中,文件可以是 .js 也可以是 .jsx,但是更推荐 .jsx
  2. 文件名首字母可以不大写,但是文件中的组件名首字母必须大写。

三、引入渲染子组件

react 复制代码
import React, { Component } from 'react'
import ClassComponent from './01-组件基础/ClassComponent'
import FunctionComponent from './01-组件基础/FunctionComponent'
export default class App extends Component {
    render() {
        return (
            <div>
                <h1>App组件</h1>
                <ClassComponent />
                <FunctionComponent />
            </div>
        )
    }
}

05 -《JSX 基础语法》

一、JSX 概念

JSX 全称,JavaScript XML。

JSX 语法,指的就是可以将 HTML 标签和 JS 代码混在一起编写。

二、JSX 基础语法

1、JSX 根节点

所有的组件中,都必须有一个最外层的根节点:

react 复制代码
import React, { Component } from 'react'
export default class JSXComponent extends Component {
    render() {
        return (
            <div>
                <h1></h1>
                <h1></h1>
                <h1></h1>
                <h1></h1>
            </div>
        )
    }
}

根节点可以用空标签来代替:

react 复制代码
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h1></h1>
                <h1></h1>
                <h1></h1>
                <h1></h1>
            </>
        )
    }
}
2、标签的特殊属性

由于 class 和 for 这两个关键字在 JS 中有其他的作用,所以标签身上的 class 和 for 属性需要替换成 classNamehtmlFor

react 复制代码
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h1 className='hello'>你好</h1>
                <label htmlFor="username"></label>
            </>
        )
    }
}
3、动态渲染数据
react 复制代码
const name = '张三';
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h1 className='hello'>你好, {name}</h1>
            </>
        )
    }
}
4、动态渲染属性
react 复制代码
const link = 'https://www.baidu.com'
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <a href={link}>百度一下</a>
            </>
        )
    }
}
5、数学运算
react 复制代码
const num1 = 100;
const num2 = 200;
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h2>{num1 + num2}</h2>
            </>
        )
    }
}
6、三目运算
react 复制代码
const age = 17;
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h3>{age >= 18 ? '已成年' : '未成年'}</h3>
            </>
        )
    }
}
7、函数调用
react 复制代码
const num1 = 100;
const num2 = 200;
const getSum = () => {
    // 计算过程
    return num1 + num2;
}
export default class JSXComponent extends Component {
    render() {
        return (
            <>
                <h2>{getSum()}</h2>
            </>
        )
    }
}

06 -《JSX 列表渲染》

一、JSX 渲染数组

React 的 JSX 语法,可以直接解析数组,将数组中的元素提取出来,进行渲染。

react 复制代码
const arr = [
    <li>张三</li>,
    <li>李四</li>,
    <li>王五</li>
]
export default class ForComponent extends Component {
    render() {
        return (
            <ul>
                {arr}
            </ul>
        )
    }
}

所以,只要我们将纯数据的数组,处理成带有节点的数组,就可以使用数组的渲染渲染。

二、JSX 的列表渲染

react 复制代码
const arr = [ '张三', '李四', "王五"]
export default class ForComponent extends Component {
    render() {
        return (
            <ul>
                {
                    arr.map((item, index) => {
                        return <li key={index}>{item}</li>
                    })
                }
            </ul>
        )
    }
}

说明:React 中循环产生的元素身上,需要通过 key 属性来设置一个唯一值。

三、循环中的条件判断

在使用 map 循环渲染数据节点时,还可以通过 if 来进行条件判断:

react 复制代码
const movieTypes = [
    { id: 1, name: '全部' },
    { id: 2, name: '现代' },
    { id: 3, name: '谍战' },
    { id: 4, name: '古装' },
]
export default class ForComponent extends Component {
    render() {
        return (       
            <div>
                {
                    movieTypes.map(item => {
                        if (item.id == 1) {
                            return <strong key={item.id}>{item.name}</strong>
                        }
                        return <span key={item.id}>{item.name}</span>
                    })
                }
            </div>
        )
    }
}

07 -《JSX 条件渲染》

一、if 条件渲染

二、三元运算

react 复制代码
const movieTypes = [
    { id: 1, name: '全部' },
    { id: 2, name: '现代' },
    { id: 3, name: '谍战' },
    { id: 4, name: '古装' },
]
export default class ForComponent extends Component {
    render() {
        return (
            <div>
                {
                    movieTypes.map(item => {
                        return item.id == 1 ? (
                            <strong key={item.id}>{item.name}</strong>
                        ) : (
                            <span key={item.id}>{item.name}</span>
                        )
                    })
                }
            </div>
        )
    }
}

三、|| 或运算符

A || B,如果 A 为真,留下 A,如果 A 为假,留下 B。

四、&& 与运算符

A && B,如果 A 为真,留下 B,如果 A 为假,留下 A。

08 -《组件内部数据》(类组件)

一、定义数据

react 复制代码
export default class StateComponent extends Component {
    state = {
        count: 1,
        student: {
            name: '张三',
            age: 20
        }
    }
    render() {
        return (
            <div>StateComponent</div>
        )
    }
}

二、使用数据

1、直接使用(不解构)
react 复制代码
export default class StateComponent extends Component {
    state = {
        count: 1,
        student: {
            name: '张三',
            age: 20
        }
    }
    render() {
        console.log(this.state.count);
        return (
            <div>
                <h1>{this.state.count}</h1>
                <h1>姓名:{this.state.student.name}</h1>
            </div>
        )
    }
}
2、解构后再使用
react 复制代码
export default class StateComponent extends Component {
    state = {
        count: 1,
        student: {
            name: '张三',
            age: 20
        }
    }
    render() {
        // const { count, student: { name, age } } = this.state;
        const { count, student } = this.state;
        const { name, age } = student;
        return (
            <div>
                <h1>{count}</h1>
                <h1>姓名:{student.name}</h1>
                <h1>年龄:{age}</h1>
            </div>
        )
    }
}

三、修改数据

React 中提供了 this.setState() 来修改数据,只有通过这种方式修改的数据,页面才会更新。

1、修改基本类型数据
react 复制代码
export default class StateComponent extends Component {
    state = {
        count: 1
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                     this.setState({
                         count: this.state.count + 1
                     })
                 }}>count+1</button>
            </div>
        )
    }
}
2、修改对象
react 复制代码
export default class StateComponent extends Component {
    state = {
        student: {
            name: '李四',
            age: 20,
            gender: '男'
        }
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                     this.setState({
                         student: {
                             ...this.state.student, // 保留其他不变的数据
                             age: this.state.student.age + 1
                         }
                     })
                 }}>age+1</button>
            </div>
        )
    }
}

四、异步的 setState

setState 方法是一个异步方法,如果想要在数据修改完成后再执行一些其他的操作,可以使用 setState 的第二个参数:

react 复制代码
export default class StateComponent extends Component {
    state = {
        count: 1
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                     this.setState({
                         count: this.state.count + 1
                     }, () => {
                         console.log(this.state.count)
                     })
                 }}>count+1</button>
            </div>
        )
    }
}

09 -《组件的事件》(类组件)

一、绑定事件

react 复制代码
export default class EventComponent extends Component {
    render() {
        return (
            <button onClick={() => {
                console.log(1111);
            }}>按钮</button>
        )
    }
}

二、事件方法(事件处理函数)

react 复制代码
export default class EventComponent extends Component {
    sayHello = () => {
        console.log('hello');
    }
    render() {
        return (
            <button onClick={this.sayHello}>按钮二</button>
        )
    }
}

三、事件传参

react 复制代码
export default class EventComponent extends Component {
    sayHi = (name) => {
        console.log('hi', name);
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.sayHi('张三');
                }}>按钮三</button>
                <button onClick={() => this.sayHi('李四')}>按钮四</button>
            </div>
        )
    }
}

四、事件对象

react 复制代码
export default class EventComponent extends Component {
    linkTo = (event) => {
        event.preventDefault();
    }
    render() {
        return (
            <div>
                <a href="" onClick={(event) => {
                    event.preventDefault();
                }}>按钮五</a>
                <a href="" onClick={this.linkTo}>按钮六</a>
                <a href="" onClick={(event) => {
                    event.preventDefault();
                    this.linkTo()
                }}>按钮七</a>
            </div>
        )
    }
}

10 -《state 操作总结》(类组件)

一、数组删除

参考语法:

react 复制代码
this.setState({
    数组名: this.state.数组.filter(item => /* 筛选条件 */)
})

参考案例:

react 复制代码
this.setState({
    goodsData: this.state.goodsData.filter(item => item.id != id)
})

二、数组修改

参考语法:

react 复制代码
this.setState({
    数组名: this.state.数组.map(item => {
        if(/* 判断条件,找到需要修改的 item */) {
            return {
                ...item, 
                要修改的属性名: 新的值
            }
        }
        return item;
    })
})

参考案例:

react 复制代码
this.setState({
    goodsData: this.state.goodsData.map(item => {
        if(item.id == id) {
            return {
                ...item, 
                count: item.count - 1
            }
        }
        return item;
    })
})

三、数组新增

参考语法:

react 复制代码
this.setState({
    数组名: [
        ...this.state.数组,
        新的值
    ]
})

参考案例:

react 复制代码
this.setState({
    goodsData: [
        ...this.state.goodsData,
        {
            id: 4,
            name: '',
            count: 100,
            price: 10
        }
    ]
})

四、对象属性的修改或新增

参考语法:

react 复制代码
this.setState({
    对象名: {
        ...this.state.对象,
        修改或新增的属性名: 新的值
    }
})

参考案例:

react 复制代码
state = {
    pageData: {
        currentPage: 1,
        pageSize: 10
    }
}
this.setState({
    pageData: {
        ...this.state.pageData,
        currentPage: this.state.pageData.currentPage + 1
    }
})

11 -《组件的样式》

一、样式的分类

  1. 内联样式:标签身上通过 style 属性设置样式
  2. 外部全局样式:不管在哪一个组件中引入,都会作用于所有组件;
  3. 外部局部样式:在哪一个组件中引入,只作用于当前组件;

二、样式的使用

1、内联样式
react 复制代码
export default class StyleComponent extends Component {
    render() {
        return (
            <div>
                <h1 style={{ color: 'red', backgroundColor: '#eee' }}>你好</h1>
                <div style={{ backgroundColor: 'green', width: 100, height: 100 }}></div>
            </div>
        )
    }
}
2、外部全局样式

外部创建 .css 文件,所有的 CSS 选择器和 CSS 样式都可以正常使用。

在任意组件中引入该文件即可:

arduino 复制代码
import './index.css'
3、外部局部样式

外部局部样式有以下几个要求:

  1. 文件名必须是 xxx.module.css
  2. 所有的选择器只能使用 class 类选择器;
  3. 引入时需要通过 import 变量名 from '路径' 来引入;
  4. 使用时通过 变量名.选择器名 来使用;
react 复制代码
import styles from './index.module.css'
export default class StyleComponent extends Component {
    render() {
        return (
            <h1 className={styles.title}>标题</h1>
        )
    }
}

12 -《生命周期》(类组件)

生命周期官网图:https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

一、分类

React 的生命周期分为三个阶段:

  1. 挂载阶段:
  2. 更新阶段:
  3. 销毁阶段:

二、常用的生命周期函数

1、挂载阶段
  1. constructor
  2. render
  3. componentDidMount:发送网络请求
2、更新阶段
  1. render
  2. componentDidUpdate
3、销毁阶段
  1. componentWillUnmount

三、不常用的生命周期函数

1、更新阶段:shouldComponentUpdate
react 复制代码
export default class LifeCycle extends Component {
    state = {
        count: 1
    }
    shouldComponentUpdate(props, state) {
        if (this.state.count == state.count) {
            return false;
        }
        return true;
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.setState({
                        count: 1
                    });
                }}>按钮</button>
            </div>
        )
    }
}
2、PureComponent
scala 复制代码
import React, { PureComponent } from 'react'
export default class LifeCycle extends PureComponent {
    state = {
        count: 1
    }
    render() {
        return (
            <div>
                <button onClick={() => {
                    this.setState({
                        count: 1
                    });
                }}>按钮</button>
            </div>
        )
    }
}

13 -《函数组件 Hook》

一、函数组件和类组件

React 16.8 版本之前,函数组件没有内部状态,也没有生命周期,所以更多的只是用函数组件来做展示组件。但是从 16.8 开始,React 新增了 Hook,让函数组件的功能得到了增强,有了自己的内部状态、生命周期等。

二、Hook 介绍

Hook,实际上就是 React 内部封装好的一组方法。我们通过调用这些 Hook 方法,就可以来设置函数组件内部的状态、生命周期等。

例如:

Hook 方法 作用
useState() 定义函数组件内部状态(数据)
useEffect() 模拟函数组件的生命周期
useMemo() 缓存数据,模拟计算属性
...

hook 使用规则

  1. 所有的 Hook 方法命名都是以 use 开头,以后我们自己定义的普通变量、函数等,命名要避开 use
  2. 所有的 Hook 方法在使用前,都必须先引入;
  3. 所有的 Hook 方法都只能在函数组件中使用,不能再嵌套在其他的条件语句、循环语句中;

14 -《函数组件 useState》

一、定义数据

react 复制代码
const StateComponent = () => {
    const [count] = useState(0);
    const [students] = useState([
        { id: 1, name: '张三', age: 20 },
        { id: 2, name: '李四', age: 20 },
    ])
    return (
        <div></div>
    )
}

useState() 的参数,就是初始数据。一个组件中,可以无限次的使用 useState

二、使用数据

函数组件中,数据的渲染和类组件一致:

react 复制代码
const StateComponent = () => {
    const [count] = useState(0);
    const [students] = useState([
        { id: 1, name: '张三', age: 20 },
        { id: 2, name: '李四', age: 20 },
    ])
    return (
        <div>
            <h1>{count}</h1>
            <ul>
                {
                    students.map(item => <li key={item.id}>{item.name}</li>)
                }
            </ul>
        </div>
    )
}

三、修改数据

useState 的返回值中,第一个是数据,第二个是修改数据的方法,通常以 set 开头来命名:

react 复制代码
const StateComponent = () => {
    const [count, setCount] = useState(0);
    const [students, setStudents] = useState([
        { id: 1, name: '张三', age: 20 },
        { id: 2, name: '李四', age: 20 },
    ])
    console.log(count); // 查看初始数据,和每次修改后的数据
    return (
        <div>
            <h1>{count}</h1>
            <button onClick={() => {
                setCount(count + 1);
            }}>count+1</button>
            <ul>
                {
                    students.map(item => <li key={item.id}>{item.name}</li>)
                }
            </ul>
            <button onClick={() => {
                setStudents(students.map(item => {
                    if (item.id == 2) {
                        return {
                            ...item,
                            age: 21
                        }
                    }
                    return item;
                }));
            }}>修改李四年龄</button>
        </div>
    )
}

语法要求:

  1. 不能直接修改原数据;
  2. 调用对应的 set 方法,传递新数据,来实现旧数据的修改;
  3. set 方法是异步方法,因此如果想要查看修改后的数据,直接在顶层输出即可。

15 -《useMemo》

一、基础语法

useMemo,可以用来缓存数据,通常当我们需要通过计算旧数据来得到一个新数据时,就可以使用 useMemo 来模拟计算属性。

react 复制代码
import React, { useMemo } from 'react'
const 变量 = useMemo(() => {
    // 计算过程
    return 值;
}, [依赖的旧数据])

二、示例代码

react 复制代码
import React, { useMemo, useState } from 'react'
const ShoppingCart = () => {
    const [goodsData, setGoodsData] = useState([
        { id: 1, name: '衣服', price: 100, count: 0 },
        { id: 2, name: '裤子', price: 200, count: 50 },
        { id: 3, name: '鞋子', price: 300, count: 20 },
    ]);
    // 计算属性 totalPrice
    const totalPrice = useMemo(() => {
        return goodsData.reduce((prev, item) => {
            return item.price * item.count + prev;
        }, 0)
    }, [goodsData]);
    return (
        <div>
            <table>
                ...
            </table>
            <div>合计:{totalPrice}元</div>
        </div>
    )
}
export default ShoppingCart

16 -《表单操作》(受控组件和非受控组件)

一、分类

  1. 受控组件:表单元素完全受 React 的控制,不受用户控制。
  2. 非受控组件:表单元素不受 React 的控制,受用户控制。

二、非受控组件

1、设置默认值

输入框如果要作为非受控组件,我们需要用 defaultValue 来设置输入框的默认值。

单复选框如果要作为非受控组件,我们需要用 defaultChekced 来设置单复选框的默认选中。

react 复制代码
const FormComponent = () => {
    return (
        <input type="text" defaultValue="hello" />
    )
}
export default FormComponent
2、获取表单元素的值

如果要获取非受控组件的值,需要通过 ref 属性来绑定元素节点,通过获取元素节点,来得到节点中值:

javascript 复制代码
import React, { useRef } from 'react'
const FormComponent = () => {
    const inputRef = useRef(null);
    console.log(inputRef);   // { current: null }
    return (
        <div>
            <input type="text" ref={inputRef} />
            <button onClick={() => {
                console.log('获取输入框节点', inputRef.current);
            }}>搜索</button>
        </div>
    )
}
export default FormComponent

三、受控组件

1、输入框
react 复制代码
import React, { useState } from 'react'
const FormComponent = () => {
    const [msg, setMsg] = useState('');
    return ( 
        <input type="text" value={msg} onChange={(e) => {
            setMsg(e.target.value)
        }} />     
    )
}
2、下拉列表
react 复制代码
import React, { useState } from 'react'
const FormComponent = () => {
    const [city, setCity] = useState('');
    return (
        <select value={city} onChange={(e) => {
            setCity(e.target.value);
        }}>
            <option value="四川">四川</option>
            <option value="贵州">贵州</option>
            <option value="云南">云南</option>
        </select>
    )
}
export default FormComponent
3、单选按钮
react 复制代码
import React, { useState } from 'react'
const FormComponent = () => {
    const [gender, setGender] = useState('');
    return (
        <div>
            <input type="radio" checked={gender == '男'} onChange={() => {
                setGender('男');
            }} />
            <label>男</label>
            <input type="radio" checked={gender == '女'} onChange={() => {
                setGender('女');
            }} />
            <label>女</label>
        </div>  
    )
}
export default FormComponent
4、单个复选框
react 复制代码
import React, { useState } from 'react'
const FormComponent = () => {  
    const [isAgree, setIsAgree] = useState(false);
    return (
        <div>
            <input type="checkbox" checked={isAgree} onChange={() => {
                setIsAgree(!isAgree);
            }} />
            <label>我已阅读并同意以上协议</label>
        </div>
    )
}
export default FormComponent
5、多个复选框
react 复制代码
import React, { useState } from 'react'
const FormComponent = () => {
    const [likes, setLikes] = useState(['睡觉']);
    return (
        <div>
            <input type="checkbox" checked={likes.includes('吃饭')} onChange={(e) => {
                if (e.target.checked) {
                    setLikes([
                        ...likes,
                        '吃饭'
                    ])
                } else {
                    setLikes(likes.filter(item => item != '吃饭'))
                }
            }} />
            <label>吃饭</label>
            <input type="checkbox" checked={likes.includes('睡觉')} onChange={(e) => {
                if (e.target.checked) {
                    setLikes([
                        ...likes,
                        '睡觉'
                    ])
                } else {
                    setLikes(likes.filter(item => item != '睡觉'))
                }
            }} />
           <label>睡觉</label>
            <input type="checkbox" checked={likes.includes('打豆豆')} onChange={(e) => {
                if (e.target.checked) {
                    setLikes([
                        ...likes,
                        '打豆豆'
                    ])
                } else {
                    setLikes(likes.filter(item => item != '打豆豆'))
                }
            }} />
            <label>打豆豆</label>
        </div>
    )
}
export default FormComponent

17 -《useEffect》

用来处理"副作用",实际上就是用来模拟类组件的生命周期。

一、箭头函数 + 空数组

当 useEffect 接收两个参数,第一个参数是回调函数,第二个参数是空数组时。

回调函数会在组件首次挂载完成 执行,模拟的是类组件中的 componentDidMount 生命周期。

通常可以用来发送页面初始化的网络请求:

react 复制代码
useEffect(() => {
    console.log('useEffect: 在组件首次挂载完成执行');
}, []);

二、箭头函数 + 非空数组

当 useEffect 接收两个参数,第一个参数是回调函数,第二个参数是非数组时,数组中可以设置多个需要"侦听"的数据。

回调函数会在组件首次挂载完成 时,并且数组中任意数据发生改变时执行。

react 复制代码
useEffect(() => {
    console.log('useEffect: 在组件首次挂载完成执行 + 数组中任意数据发生改变');
}, [数据一, 数据二]);

三、箭头函数

当 useEffect 接收一个参数,这个参数是一个回调函数。

回调函数会在组件首次挂载完成 时,并且组件更新时 执行,模拟的是类组件中的 componentDidMount + componentDidUpdate 生命周期。

react 复制代码
useEffect(() => {
    console.log('useEffect: 在组件首次挂载完成执行 + 组件更新');
});

四、第一个函数中返回新函数

当 useEffect 接收一个函数作为参数,同时函数中又 return 了一个新函数。

return 的这个新函数,会在组件卸载完成前执行,模拟的是类组件中的 componentWillUnmount 生命周期。

react 复制代码
useEffect(() => {
    return () => {
        console.log('返回的新函数:在组件卸载完成前执行')
    }
}, []);

18 -《组件通信》

一、父传子:props

1、父组件传值
javascript 复制代码
const FatherComponent = () => {
    return (
        <ChildA name="张三" age={20} />
    )
}

传值时,除了传递静态的字符串(例如上面的"张三"),其他数据在传递时都通过 {} 来传值。

2、子组件接收值
javascript 复制代码
const ChildA = (props) => {
    console.log(props);
    const { name } = props;
    return (
        <div>
            <h3>{name}</h3>
            <h3>{props.age}</h3>
        </div>
    )
}
3、设置 props 的默认值
javascript 复制代码
const ChildA = (props) => {
    // 方式一:通过 ES6 的解构赋值来设置默认值
    const { name = '李四' } = props;
    return (
        <div>
            <h3>{name}</h3>
            <h3>{props.age}</h3>
        </div>
    )
}
// 方式二:React 官方方式
ChildA.defaultProps = {
    age: 18
}
4、props 的验证
javascript 复制代码
import pt from 'prop-types'
const ChildA = (props) => {
    const { name = '李四' } = props;
    return (
        <div>
            <h3>{name}</h3>
            <h3>{props.age}</h3>
        </div>
    )
}
// 设置 props 的验证
ChildA.propTypes = {
    name: pt.string,
    age: pt.oneOfType([pt.number, pt.string])
}
export default ChildA

常用的验证规则:

  • 字符串:pt.string
  • 数字:pt.number
  • 布尔值:pt.bool
  • 数组:pt.array
  • 对象:pt.object
  • 函数:pt.func
  • 多个中的任意一个:pt.oneOfType([pt.number, pt.string])
5、props 只读

props 中的数据,都只能使用,不能修改!!!

二、子传父:回调函数

父组件先传递一个函数给子组件,子组件中调用父组件的方法,同时传值给父组件。

1、父组件传递回调函数
javascript 复制代码
const FatherComponent = () => {
    const getChildData = (data) => {
        console.log('接收子组件传递的参数', data);
    }
    return (
        <div>
            <ChildA name="张三" age={20} getChildData={getChildData} />
        </div>
    )
}
2、子组件调用回调函数并传值
javascript 复制代码
const ChildA = (props) => {
    return (
        <div>
            <button onClick={() => {
                // 子组件调用父组件的方法,并将值传递给父组件
                props.getChildData('你好');
            }}>传值给父组件</button>
        </div>
    )
}

三、嵌套组件传值:context

1、创建 context 对象

我们在组件外部创建一个 context.js 文件:

javascript 复制代码
import { createContext } from "react";
export default createContext(null);
2、顶层组件传值
javascript 复制代码
import Context from './context.js'
const FatherComponent = () => {
    return (
        <Context.Provider value={{ count: 10 }}>
            <ChildA name="张三" age={20} getChildData={getChildData} />
            <ChildB />
        </Context.Provider>
    )
}

语法说明:

  1. 顶层组件通过 <Context.Provider>value 属性来传递公共数据;
  2. 只要被 <Context.Provider> 包裹的组件,其内部子子孙孙组件都可以获取到 value 中的公共数据;
3、内部组件接收值
javascript 复制代码
import React, { useContext } from 'react'
import Context from './context'
const Grandson = () => {
    const value = useContext(Context);
    console.log(value);  // { count: 10 }
    return (
        <div>Grandson</div>
    )
}

四、兄弟组件传值:事件总线

React 中默认不支持兄弟组件传值,需要我们通过"事件总线"来实现兄弟组件传值,需要下载第三方插件。

1、下载插件
csharp 复制代码
yarn add events
2、创建事件总线对象

在组件外部创建一个 event.js文件,用来创建事件总线对象:

arduino 复制代码
import { EventEmitter } from 'events';
export default new EventEmitter();
3、接收数据的组件添加方法
react 复制代码
import React,{useEffect } from 'react'
import event from'./event.js'
//接收数据的组件,红责给事件总线添加方法
const childB=()=>{
 useEffect(()=>{
  event.addListener('getData',(data)=>{
   console.log('组件B接收到的A组件传递的值:',data);
   })
},[])
 return(
 <div></div>
 )
}
4、传递数据的组件调用方法
vbnet 复制代码
import event from './event";
const childA =()=>{
   return(
     <button onclick={()=>{
       //调用 event 身上的方法,并传值
       event.emit('getData','hello');
     }}>传值给B</button>
  )
}
五、总结
  1. 父传子:props
  2. 子传父:回调函数
  3. 兄弟组件:事件总线、状态提升(兄弟之间通过父组件来传值)
  4. 嵌套组件:context
相关推荐
HUMHSX37 分钟前
Vue 项目启动全流程解析:从入口文件到全局指令注册与页面渲染
前端·javascript·vue.js
有颜有货1 小时前
PMC生产排产的4种算法,一次讲清
java·服务器·前端
小虎牙0071 小时前
Android kotlin图片库Coil源码详解
android·前端
随风一样自由1 小时前
【前端领域】前端开发核心应用场景与落地实践
前端·前端框架
an317421 小时前
弹窗数据流设计的两种高阶架构实践
前端·vue.js·架构
谢尔登2 小时前
【React】 状态管理方案
前端·react.js·前端框架
用户2136610035722 小时前
Vue商品详情与放大镜组件
前端·javascript
半个落月2 小时前
从Tapas小Demo理清localStorage、事件与this
前端·javascript
李明卫杭州2 小时前
Vue2 中 v-model 处理不同数据结构的技巧
前端·javascript·vue.js
李明卫杭州2 小时前
使用 computed 处理 v-model 复杂数据结构
前端·javascript·vue.js