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
相关推荐
2401_878454531 小时前
Themeleaf复用功能
前端·学习
葡萄城技术团队3 小时前
基于前端技术的QR码API开发实战:从原理到部署
前端
八了个戒4 小时前
「数据可视化 D3系列」入门第三章:深入理解 Update-Enter-Exit 模式
开发语言·前端·javascript·数据可视化
noravinsc5 小时前
html页面打开后中文乱码
前端·html
小满zs5 小时前
React-router v7 第四章(路由传参)
前端·react.js
小陈同学呦5 小时前
聊聊双列瀑布流
前端·javascript·面试
键指江湖6 小时前
React 在组件间共享状态
前端·javascript·react.js
诸葛亮的芭蕉扇6 小时前
D3路网图技术文档
前端·javascript·vue.js·microsoft
小离a_a6 小时前
小程序css实现容器内 数据滚动 无缝衔接 点击暂停
前端·css·小程序
徐小夕7 小时前
花了2个月时间研究了市面上的4款开源表格组件,崩溃了,决定自己写一款
前端·javascript·react.js