Web学习笔记-React(组合Components)

news2024/11/26 16:42:17

笔记内容转载自 AcWing 的 Web 应用课讲义,课程链接:AcWing Web 应用课。

CONTENTS

    • 1. 创建父组件
    • 2. 从上往下传递数据
    • 3. 传递子节点
    • 4. 从下往上调用函数

本节内容是组件与组件之间的组合,例如用不同组件构成 DOM 树,以及给不同的组件传递数据或者调用不同组件的方法,还有不同组件的生命周期。

1. 创建父组件

我们还是继续在之前的 Box 组件上进行操作,首先创建一个 Boxes 组件,其中包含一系列 Box 组件。

components 目录中创建 boxes.jsx

import React, { Component } from 'react';

class Boxes extends Component {
    state = {  } 
    render() { 
        return (
            <h1>Boxes</h1>
        );
    }
}
 
export default Boxes;

然后修改一下 index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import Boxes from './components/boxes';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Boxes />);

现在我们在 Boxes 中加入多个 Box,当一个组件中包含多个并列元素的时候,需要用一个标签将他们括起来,可以使用 React 中的一个虚拟标签 <React.Fragment>

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = {  } 
    render() { 
        return (
            <React.Fragment>
                <Box />
                <Box />
                <Box />
            </React.Fragment>
        );
    }
}
 
export default Boxes;

为了方便也可以用一个数组来表示,将 Box 的信息存到 state 里,由于 React 组件如果有若干个儿子那么他们的 key 需要不一样,因此还需要存一个唯一的 id

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = { 
        boxes: [
            {id: 1, x: 0},
            {id: 2, x: 0},
            {id: 3, x: 0},
            {id: 4, x: 0},
        ]
     } 
    render() { 
        return (
            <React.Fragment>
                {this.state.boxes.map(box => (
                    <Box key={box.id} />
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

2. 从上往下传递数据

通过 this.props 属性可以从上到下传递数据。例如我们在 Boxes 中传递 x

...

class Boxes extends Component {
    state = { 
        ...
     } 
    render() { 
        return (
            <React.Fragment>
                {this.state.boxes.map(box => (
                    <Box key={box.id} x={box.x} name='yyj' />
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

可以在 Box 中输出信息 console.log(this.props); 查看内容:

在这里插入图片描述

修改 Box 中的 x

import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component {  // 输入cc即可补全
    state = { 
        x: this.props.x,
    };

    ...
}
 
export default Box;

3. 传递子节点

可以将标签写成 <Box></Box> 的形式,然后在标签中添加子标签:

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = { 
        boxes: [
            {id: 1, x: 0},
            {id: 2, x: 0},
            {id: 3, x: 0},
            {id: 4, x: 0},
        ]
     } 
    render() { 
        return (
            <React.Fragment>
                {this.state.boxes.map(box => (
                    <Box key={box.id} x={box.x} name='yyj'>
                        <h1>Title</h1>
                    </Box>
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

这样 this.props 中会多一个属性 children,可以使用 [] 单独访问某个子标签。我们可以将这个传过来的值定义在任何地方,例如可以放到每个 Box 组件的最上方:

import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component {  // 输入cc即可补全
    state = { 
        x: this.props.x,
    };

    handleClickLeft = (step) => {
        this.setState({
            x: this.state.x - step
        });
    }

    handleClickRight = (step) => {
        this.setState({
            x: this.state.x + step
        });
    }

    handleClickLeftTmp = () => {
        this.handleClickLeft(10);
    }

    render() {  // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        console.log(this.props);
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            {this.props.children}
            <div style={this.getStyles()}>{this.state.x}</div>
            <button onClick={this.handleClickLeftTmp} className='btn btn-primary m-2'>Left</button>
            <button onClick={() => this.handleClickRight(10)} className='btn btn-success m-2'>Right</button>
        </React.Fragment>
        );
    }

    getStyles() {
        ...
    }
}
 
export default Box;

4. 从下往上调用函数

父元素可以通过 this.props 向子元素传递信息,子元素也可以使用函数向父元素传递信息。假设我们需要实现通过点击删除按钮删除某个 Box,其信息保存在 Boxesstate 中,但是我们点击触发事件是在 Box 中(注意:每个组件的 this.state 只能在组件内部修改,不能在其他组件内修改)。

我们可以在父元素中定义好函数,然后将函数传给子元素:

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = { 
        boxes: [
            {id: 1, x: 0},
            {id: 2, x: 0},
            {id: 3, x: 0},
            {id: 4, x: 0},
        ]
    }

    handleDelete = (boxId) => {
        // 遍历一遍state.boxes,将box.id不为传入的参数boxId的数据保留下来
        const res = this.state.boxes.filter(box => box.id !== boxId);
        this.setState({boxes: res});
    }

    render() { 
        return (
            <React.Fragment>
                {this.state.boxes.map(box => (
                    <Box key={box.id} id={box.id} x={box.x} name='yyj'
                        onDelete={this.handleDelete}
                    />
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

这样子元素就能调用函数对父元素进行操作了:

import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component {  // 输入cc即可补全
    ...

    render() {  // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        console.log(this.props);
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            ...
            <button onClick={() => this.props.onDelete(this.props.id)} className='btn btn-danger m-2'>Delete</button>
        </React.Fragment>
        );
    }

    getStyles() {
        ...
    }
}
 
export default Box;

现在我们在 Boxes 中实现一个 Reset 按钮实现清空所有 Boxx

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = { 
        boxes: [
            {id: 1, x: 0},
            {id: 2, x: 1},
            {id: 3, x: 2},
            {id: 4, x: 3},
        ]
    }

    handleDelete = (boxId) => {
        ...
    }

    handleReset = () => {
        const res = this.state.boxes.map(box => {
            return {
                id: box.id,
                x: 0,
            }
        });
        this.setState({boxes: res});
    }

    render() {
        console.log(this.state.boxes);
        return (
            <React.Fragment>
                <button
                    onClick={this.handleReset}
                    style={{marginBottom: '15px'}}
                    className='btn btn-info'
                >Reset</button>
                {this.state.boxes.map(box => (
                    <Box key={box.id} id={box.id} x={box.x} name='yyj'
                        onDelete={this.handleDelete}
                    />
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

在控制台观察时可以发现点击 Reset 按钮后 x 确实置零了,但是 Box 显示出来的 x 并没有改变,这是因为 state 值不能在外部修改,因此我们可以将 Box 中的 state 删掉,需要在该组件中渲染外面的 state 的值。

每个维护的数据仅能保存在一个 this.state 中,不要直接修改 this.state 的值,因为 setState 函数可能会将修改覆盖掉。

修改 Boxes,将之前 Box 中操作 state 的函数转移过来:

import React, { Component } from 'react';
import Box from './box';

class Boxes extends Component {
    state = { 
        boxes: [
            {id: 1, x: 0},
            {id: 2, x: 1},
            {id: 3, x: 2},
            {id: 4, x: 3},
        ]
    }

    handleDelete = (boxId) => {
        // 遍历一遍state.boxes,将box.id不为传入的参数boxId的数据保留下来
        const res = this.state.boxes.filter(box => box.id !== boxId);
        this.setState({boxes: res});
    }

    handleReset = () => {
        const res = this.state.boxes.map(box => {
            return {
                id: box.id,
                x: 0,
            }
        });
        this.setState({boxes: res});
    }

    // 需要知道修改的是哪个box
    handleClickLeft = (box) => {
        const boxes = [...this.state.boxes];  // 浅拷贝一份
        const k = boxes.indexOf(box);  // 传入的box是引用,找出其在boxes中的下标k
        boxes[k] = {...boxes[k]};  // 再clone一遍,相当于创建新的state,深拷贝
        boxes[k].x--;
        this.setState({boxes: boxes});
    }

    handleClickRight = (box) => {
        const boxes = [...this.state.boxes];
        const k = boxes.indexOf(box);
        boxes[k] = {...boxes[k]};
        boxes[k].x++;
        this.setState({boxes: boxes});
    }

    render() {
        return (
            <React.Fragment>
                <button
                    onClick={this.handleReset}
                    style={{marginBottom: '15px'}}
                    className='btn btn-info'
                >Reset</button>

                {this.state.boxes.map(box => (
                    <Box key={box.id} id={box.id} x={box.x} name='yyj'
                        onDelete={this.handleDelete}
                        onClickLeft={() => this.handleClickLeft(box)}
                        onClickRight={() => this.handleClickRight(box)}
                    />
                ))}
            </React.Fragment>
        );
    }
}
 
export default Boxes;

然后修改 Box,将 this.state 替换成父组件传递过来的 props

import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component {  // 输入cc即可补全
    render() {  // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
        return (
        // HTML标签中可以使用{}写一个表达式
        <React.Fragment>
            <div style={this.getStyles()}>{this.props.x}</div>
            <button onClick={this.props.onClickLeft} className='btn btn-primary m-2'>Left</button>
            <button onClick={this.props.onClickRight} className='btn btn-success m-2'>Right</button>
            <button onClick={() => this.props.onDelete(this.props.id)} className='btn btn-danger m-2'>Delete</button>
        </React.Fragment>
        );
    }

    getStyles() {
        let styles = {
            width: '50px',
            height: '50px',
            backgroundColor: 'lightblue',
            color: 'white',
            textAlign: 'center',
            lineHeight: '50px',
            borderRadius: '5px',
            position: 'relative',
            left: this.props.x
        };

        if (this.props.x === 0) {
            styles.backgroundColor = 'orange';
        }

        return styles;
    }
}
 
export default Box;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/993104.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

看完这篇 教你玩转渗透测试靶机Vulnhub——Momentum:2

Vulnhub靶机Momentum:2渗透测试详解 Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;漏洞发现&#xff1a;③&#xff1a;文件上传漏洞利用&#xff1a;…

【C++基础】8. 函数

文章目录 【 1. 函数的定义 】【 2. 函数声明 】【 3. 调用函数 】【 4. 函数参数 】4.1 传值调用4.2 指针调用4.3 引用调用 【 5. 形参默认值 】【 6. lambda函数 】 函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数&#xff0c;即主函数 main() 。可以把代码…

Fiddler工具使用汇总

Fiddler工作原理 fiddler作为一个代理服务器&#xff0c;跟浏览器建立连接之后&#xff0c;浏览器像目标服务器发送的请求都会经过fiddler代理&#xff0c;所以fiddler可以捕获到http&#xff08;s&#xff09;请求&#xff0c;从而可以解释、分析、甚至重写发出去的http&…

[De1CTF 2019]SSRF Me | BUUCTF

根据题目名我们知道这是一道SSRF的题目 它允许攻击者在受害服务器上发起未经授权的网络请求 分析 在buuctf上有一个提示 也就是说flag在 网站的flag.txt 访问主页 很明显是段flask代码 格式化后 from flask import Flask, request # 导入Flask和request模块 import sock…

设备管理系统的优势是什么?设备管理系统对企业运营管理有什么帮助?

传统的设备报修维护方式存在一些问题&#xff0c;例如指派传递速度慢和故障信息不准确等。然而&#xff0c;使用设备管理系统就可以轻松地解决这些问题&#xff0c;并且报修全流程只需短短的30秒。设备管理系统具有许多优势&#xff0c;首先它支持多种渠道的报修&#xff0c;包…

《TCP/IP网络编程》阅读笔记--进程间通信

目录 1--进程间通信 2--pipe()函数 3--代码实例 3-1--pipe1.c 3-2--pipe2.c 3-3--pipe3.c 3-4--保存信息的回声服务器端 1--进程间通信 为了实现进程间通信&#xff0c;使得两个不同的进程间可以交换数据&#xff0c;操作系统必须提供两个进程可以同时访问的内存空间&am…

初出茅庐的小李博客之数制与编码知识

模拟量与数字量&#xff1a; 数字量和模拟量是两种用于表示和处理不同类型数据的概念&#xff0c;常见于电子和计算机系统中。它们在信号处理、传感器技术、通信和控制系统中有不同的应用。 1. 数字量&#xff08;Digital&#xff09;&#xff1a; 数字量是离散的&#xff0…

06文本搜索工具——grep以及正则表达式

一、grep工具的使用 可以通过返回状态码判断文件有没有这个数据&#xff0c;有状态码为0&#xff0c;没有为1。文件不存在状态码为2 -o&#xff1a; 二、正则表达式 1、基本正则表达式 .为匹配任意字符&#xff0c;..两个两个匹配任意字符&#xff0c;...三个三个匹配任意字符 …

群拼团接龙小程序源码功能和开发

针对微信群开发的拼团接龙小程序&#xff0c;有点快团团的味道。是做私域非常不错的一款小程序。 小程序基于Uniapp开发&#xff0c;目前适配了微信小程序。 接龙&#xff1a; 在小程序中可以创建自定义接龙&#xff0c;不需要复杂的申请流程。 商品发布&#xff1a; 接龙…

模板测试和深度测试在cocoscreator中的应用

模板测试(Stencil Test)&#xff1a; 当片段着色器处理完一个片段之后&#xff0c;模板测试(Stencil Test)会开始执行&#xff0c;和深度测试一样&#xff0c;它也可能会丢弃片段。接下来&#xff0c;被保留的片段会进入深度测试&#xff0c;它可能会丢弃更多的片段。模板测试…

React 开发一个移动端项目(1)

技术栈&#xff1a; 项目搭建&#xff1a;React 官方脚手架 create-react-appreact hooks状态管理&#xff1a;redux 、 redux-thunkUI 组件库&#xff1a;antd-mobileajax请求库&#xff1a;axios路由&#xff1a;react-router-dom 以及 historyCSS 预编译器&#xff1a;sass…

Web开发后端总结

Web后端开发现在基本上都是基于标准的三层架构进行开发的&#xff0c;在三层架构当中&#xff0c;Controller控制器层 - 负责接收请求响应数据&#xff0c;Service - 业务层负责具体的业务逻辑处理&#xff0c;而Dao - 数据访问层也叫持久层&#xff0c;就是用来处理数据访问操…

第9节-PhotoShop基础课程-移动抓手缩放工具

文章目录 前言1. 移动工具1.移动工具1.自动选择&#xff08;图层和组&#xff09;2.显示变换控件 &#xff08;Shift 变换/ Ctrl 变换&#xff09;3.自由变换 Ctrl T &#xff08;Shift 变换/ Ctrl 变换&#xff09;4.对齐功能 2.画板工具 V1. 创建画板并作图2.导出画板 2.路…

【strcpy函数和strncpy函数的对比与模拟实现】

strcpy函数和strncpy函数的对比与模拟实现 1.strcpy函数介绍 资源来源于cplusplus网站 大致意思就是&#xff1a; 它的作用为&#xff1a; 将一个字符串复制到另一块空间地址中 的函数&#xff0c;‘\0’是停止拷贝的终止条件&#xff0c;同时也会将 ‘\0’ 也复制到目标空间…

redis集群最少使用三个主节点和使用16384个槽以及主节点数量不超过1000的原因

目录 集群最少三个主节点的原因 为什么是三个? 为什么是奇数? 16384个槽和1000个主节点 集群最少三个主节点的原因 https://redis.io/docs/management/scaling/ 官网建议&#xff0c;搭建 redis 集群最少三主三从。 但是这么做是出于什么考虑呢&#xff1f; https://workt…

02深度学习目标检测方法介绍-传统

一、目标学习的检测方法变迁及对比 “目标检测“是当前计算机视觉和机器学习领域的研究热点。从Viola-Jones Detector、DPM等冷兵器时代的智慧到当今RCNN、YOLO等深度学习土壤孕育下的GPU暴力美学&#xff0c;整个目标检测的发展可谓是计算机视觉领域的一部浓缩史。整个目标检测…

Python实操 PDF自动识别并提取Excel文件

最近几天&#xff0c;paddleOCR开发了新的功能&#xff0c;通过将图片中的表格提取出来&#xff0c;效果还不错&#xff0c;今天&#xff0c;作者按照步骤测试了一波。 首先&#xff0c;讲下这个工具是干什么用的&#xff1a;它的功能主要是针对一张完整的PDF图片&#xff0c;可…

EasyAVFilter代码示例之将摄像机RTSP流转成RTMP推流输出

以下是一套完整的RTSP流转RTMP推流功能的开发源码&#xff0c;就简简单单几行代码&#xff0c;就可以完成原来ffmpeg很复杂的调用流程&#xff0c;而且还可以集成在自己的应用程序中调用&#xff0c;不需要再单独一个ffmpeg的进程来调用&#xff0c;方法很简单&#xff1a; #i…

spring中的@Configuration配置类和@Component

在Spring的开发工作中&#xff0c;基本都会使用配置注解&#xff0c;尤其以Component及Configuration为主&#xff0c;当然在Spring中还可以使用其他的注解来标注一个类为配置类&#xff0c;这是广义上的配置类概念&#xff0c;但是这里我们只讨论Component和Configuration&…

盲盒小程序开发方案

盲盒游戏作为一种富有趣味性和收藏价的虚拟盲盒产品&#xff0c;近年来在游戏市场中备受关注。本文将深入探讨盲盒游戏的开发方案&#xff0c;从市场趋势分析、用户体验设计、商业模式选择等多个维度&#xff0c;为开发者提供业且有深度的思考&#xff0c;以帮助他们在盲盒游戏…