当前位置: 首页 > news >正文

前端开发:React(3)—— 组件运作和事件处理

在进行本文的学习之前要确保有以下前置学习:

  • 对HTML、JavaScript有基础学习
  • 对React组件有基础认识,能够创建一个正确的React组件

前面我们很浅显地了解了React,知道了如何去定义,以及导入导出的操作;在接下来我们真正开始使用React时,需要不断用到HTML和JavaScript部分的知识,我们一定要打好基础,才能开始上手React部分的内容。

在正式开始之前,我们先来看一下运行环境。本文中程序的运行全部都在vscode上进行,我们也推荐大家使用vscode来书写代码,除了开发环境清晰方便,其上也有许多好用的组件,对我们的开发能提供很大帮助。好了,话不多说,我们直接开始:

目录

vite入门

观察文件

多个组件

创建组件与使用

使用props进行传参

动态渲染

事件处理


vite入门

一个简单的入门方法是使用vite工具。首先要确保我们已经安装使用npm。我们创建一个demo的应用程序,导航到目录并进行安装:(在cmd或vscode下载terminal组件使用)

npm create vite@latest demo -- --template react

然后我们进入刚刚创建好的文件夹安装环境:

cd demo 
npm install

等待安装好之后我们运行:

npm run dev

控制台显示应用程序已在本地主机端口上启动,点击链接打开即可。

我们可以看到运行后的页面为:

点击count,发现会随着点击而计数。

观察文件

我们打开控制台(fn + F12),并且要时刻能看到vscode中的代码。我们在进行代码编写时可以随时运行,观察网页中页面的变化和控制台中的信息来判断我们是否达到了想要的效果。

下面我们打开src文件夹,找到main.jsx文件。它是运行时程序的入口。我们再找到App.jsx文件,这里面就是我们编写与存放React组件的位置了。至于App.css与index.css我们可以先删掉,关于样式的修改本文中不会讨论。接下来我们对main.jsx和App.jsx文件做出修改:

main.jsx文件:

import ReactDOM from 'react-dom/client'import App from './App'ReactDOM.createRoot(document.getElementById('root')).render(<App />)

main文件的前两行为导入相关文件用于使用;最后一行表示使用App.jsx中的App组件。

App.jsx文件:

const App = () => {return (<div><p>Hello world</p></div>)
}export default App

我们重点关注App.jsx文件。可以看到App就是我们之前讲过的React组件。只是在导出的时候我们单独放在了最后一行:

export default App

导出的操作可能经常会忘记,所以我们在这里做出特别提醒:一定要记得将React组件导出!

我们来仔细观察App.jsx文件;组件App的创建与我们之前的介绍有些不同。我们之前是使用function创建函数,而这里则是使用箭头函数并赋值给App变量使其成为一个组件。我们在JS的文章中介绍了函数的创建方法,其中之一就是以变量赋值的形式进行创建。需要的可以点击前往:函数

我们看一下区别:

const App = function NAME() {return ...
}const App = () => {return...
}

我们可以发现使用箭头函数可以使代码更加简洁。它将function进行了省略,并且创建了一个匿名函数。这种箭头函数的方法类似于JAVA中的Lambda表达式。

在return语句中使用()将内容包裹。而()中类似于HTML的写法为React特有的JSX型语法,在编译时会自动转换为JS语法。使用JSX能够让我们在代码书写时更加方便。

多个组件

在开发时的核心思想就是将App作为一个核心组件,再通过App调用其他功能的组件;主组件负责整的功能框架,具体功能由其他的子组件实现;当然,核心组件也可以有多个,最后导出让main文件使用即可。

此外,在React中已经有一些现成的组件可以供我们直接使用,只需要在文件的开头进行导入。

下面我们来看一下有关创建多个组件。在之前的文章中我们提到在组件内的嵌套式创建是不背允许的。也就是说:

一个组件不能够被定义在另一个组件的内部。

比如下面的组件定义方法就不可行:

const App = () => {const Text = () => {return(<div>...</div>)} 
//不能在组件内部定义另一个组件!!return (<div>...</div> )
}

所以我们再来总结一下创建组件需要注意的事项:

  • 创建的组件名称必须要首字母大写
  • 创建的组件不能定义在另一个组件的内部
  • 组件的return语句在有多个标签时需要使用()包裹;若只有一个则可以不用使用()但是需要写在同一行
  • 在return语句中的语法类似于HTML,这种写法为JSX
  • 核心组件一定要记得导出
  • 在核心组件中一定要有对其他组件的引用,否则其他组件不能发挥功能

所以正确的组件创建思路如下:

const Text = () => {return(<div>...</div>)} onst App = () => {return (<div>...<Text ... / > //引用组件; "..." 为需要传入的属性参数...</div> )
}

    根据上面的内容,我们可以梳理一下程序的运行思路:main文件作为入口进入并按顺序执行;在main文件中有核心组件(如App)的导入;程序进入App组件开始执行,在App组件内有多个能实现不同功能的组件入口,当满足相应条件时进入对应的组件开始执行;程序在各组件内部执行后通过return语句返回标签语句内容,呈现在网页上。

    现在我们基本了解了React的作用和使用思路,我们带着这个思路开始我们的第一个React组件设计。

    创建组件与使用

    下面我们就来动手实现一下。我们使用箭头函数创建一个App组件:

    const App = () => {return (<div><h1>React</h1></div>)
    }export default App 

    然后我们运行,能够在画面上看到React字样。在后面的书写时,我们要随时保持网页的控制台打开,便于我们观察代码的效果和发现错误修改bug。

    下面我们试着编写一个Hello组件,功能是打印一行段落 Hello world!

    这时就需要用到多个组件的创建与引用了。我们先创建好Hello组件:

    const Hello = () => {return (<div><p>Hello world!</p></div>)
    }

    然后我们在App中进行引用:

    const App = () => {return (<div><h1>React</h1><Hello />//引用Hello组件</div>)
    }

    我们通过这样的方式救能简单实现组件的创建和引用了。但类似于函数,我们除了在组件中进行字符的打印,当然也可以设置参数进行运算。那么这样又该怎么实现呢?不同组件之间又该怎样进行参数的传递?

    使用props进行传参

    在上面的例子中,我们对Hello组件做一点修改:

    const Hello = (props) => {return (<div><p>Hello {props.text}</p></div>)
    }

    可以看到,我们在括号中加入了props,它救表示我们传入的参数。我们假设props有一个text属性,按照上面的方式在大括号中使用 props. 属性名 就能使用我们传入的属性了。

    那么我们怎样通过App向Hello组件传入参数呢?直接在前面的引用方式中加入属性内容即可:

    <Hello text = "world!"/>

    我们运行一下发现和之前的代码效果相同。

    当然我们也可以传入变量,可以在引用时定义,也可以提前创建好。这里同样使用于全局变量和局部变量的规则;规定的变量只能在其规定的范围中才能使用。比如:

    const App = () => {const age = 12const name = "peter"return (<div><h1>React</h1><Hello name={name} age={age}/><Hello name="Alex" age="30"/></div>)
    }

    使用参数时用大括号进行包裹。然后我们在Hello中进行引用:

    const Hello = (props) => {return (<div><p>Hello {props.name}, your age is {props.age} years old.</p></div>)
    }

    点击运行,发现打印了两行段落:

    我们在Hello组件中添加一行console代码来观察props存储的值:

    console.log(props)

    然后就能在控制台中看到如下信息:

    就是我们传入的两组参数。

    不过我们在App传入参数的时候,不一定要传入我们所定义的全部参数;因此我们定义props的属性时,也可以放在Hello组件内部去定义。

    我们可以使用如下的方式:

    const Hello = (props) => {const name = props.nameconst age = props.ageconsole.log(props)return (<div><p>Hello {name}, your age is {age} years old.</p></div>)
    }const App = () => {const name = "Daisy"const age = "24"return (<div><h1>React</h1><Hello name="peter" age="10"/><Hello name="Alex" age="30"/><Hello name={name} age={age} /></div>)
    }export default App 

    这样我们就能直接在组件内部使用属性名而不用加上props.前缀。我们还可以对参数的定义进行简化:

    const {name,age} = props

    函数也可以创建。我们再用一个新的例子来看:

    const Hello = (props) => {const { name, age } = propsconst bornYear = () => new Date().getFullYear() - agereturn (<div><p>Hello {name}, you are {age} years old</p><p>So you were probably born in {bornYear()}</p></div>)
    }const App = () => {const name = 'Peter'const age = 10return (<div><h1>Greetings</h1><Hello name="Maya" age={26 + 10} /><Hello name={name} age={age} /></div>)
    }export default App 

    运行一下:

    通过上述的例子,我们已经成功掌握props的用法,知道了如何创建、传入和使用

    参数。但如果想要熟练掌握和灵活运用,还需要我们进行反复的练习。

    动态渲染

    前面我们都是创建的静态页面,页面上所有的内容都是静止不动的,有无法和网页内容进行交互。下面我们来学习如何制作一个动态的网页。

    我们来构建一个能随时变化的计数器。

    main文件不变:

    import ReactDOM from 'react-dom/client'import App from './App'ReactDOM.createRoot(document.getElementById('root')).render(<App />)

    我们在App文件中导入功能useState,这是在React库中已经编写好的,我们导入后就能使用。其导入的代码为:

    import { useState } from "react"

    useState使用后方法如下:

    const [ counter, setCounter ] = useState(0)
    

    counter为我们创建的变量,它的初始值等于useState()的括号中的内容;setCounter可以看做一个函数,决定变量(counter)的变化规则。第二个参数的命名必须以“set”作为开头。

    我们再使用setTimeout函数实现计数器操作;先看整体代码:

    import { useState } from 'react'const App = () => {const [ counter, setCounter ] = useState(0)setTimeout(() => setCounter(counter + 1),1000)return (<div>{counter}</div>)
    }export default App

    setTimeout接受两个参数,第一个表示变化的数值规则;第二个表示变化时打印的延时。由于计算机的计算速度很快,我们需要设定延时才能很好得观察到数值的变化。

    运行一下,可以看到计数器在缓慢地增加。

    事件处理

    事件起始就是用户进行的交互行为,例如点击、选择等。我们之前在HTML和JavaScript的学习中有过事件的讲解,其实和这里React中的本质上是相同的。我们来看最简单的按钮:

    <button onClick={}></button>

    在大括号中写入的是点击后的效果;我们先设计一个点击了就会打印‘clicked’的效果:
    这里我们直接在大括号中使用箭头函数,当函数的内容只有一行代码时,可以省略大括号。

    const App = () => {return (<div><button onClick={()=>console.log('clicked')}>按钮</button></div>)
    }
    export default App

    用户通过点击,控制台上就会打印做出反馈。这就是一个事件。我们可以利用事件和上面的计数器变化逻辑设计一些代码:当用户点击plus按钮时,数字就会加1;点击zero按钮时,数字就会置零:

    import { useState } from "react"const App = () => {const [ counter, setCounter ] = useState(0)const increaseByOne = () => setCounter(counter + 1)const setToZero = () => setCounter(0)return (<div><div>{counter}</div><button onClick={increaseByOne}>plus</button><button onClick={setToZero}>zero</button></div>)
    }
    export default App

    我们在return语句中位点击事件调用了两个对应的函数。increaseByOne函数实现加一效果;setToZero实现置零效果。在上述的基础上,你能否再实现一个减一的效果?

    我们最后来看一个练习代码,你能否在不运行代码的情况下分析出该代码有什么功能?

    import { useState } from "react"const Display = (props) => {return (<div>{props.counter}</div>)
    }const Button = (props) => {return (<button onClick={props.onClick}>{props.text}</button>)
    }const App = () => {const [counter, setCounter] = useState(0)console.log('rendering with counter value', counter)const increaseByOne = () => {console.log('increasing, value before', counter)setCounter(counter + 1)}const decreaseByOne = () => { console.log('decreasing, value before', counter)setCounter(counter - 1)}const setToZero = () => {console.log('resetting to zero, value before', counter)setCounter(0)}return (<div><Display counter={counter} /><Button onClick={increaseByOne} text="plus" /><Button onClick={setToZero} text="zero" /><Button onClick={decreaseByOne} text="minus" /></div>)
    } export default App


     

      http://www.dtcms.com/a/326254.html

      相关文章:

    • 【论文阅读】BEVFormer论文解析及Temporal Self-Attention、Spatial Cross-Attention注意力机制详解及代码示例
    • 如何平衡短期与长期需求
    • PCIE 设备百科
    • 【运维进阶】LAMPLNMP 最佳实践
    • MPXxx6115A Series的概述以及 MPXxx6115A series 用OSS-ECAL的提供情况
    • Pytest 全流程解析:执行机制与报告生成实战指南
    • html转成markdown(1.0.0)
    • Eino中的两种应用模式:“单独使用”和“在编排中使用”
    • ZKmall开源商城多商户架构:平衡管理与运营的技术方案
    • 【lucene】livedocs描述
    • 如何开始创业?
    • OpenBMC中phosphor-ipmi-host深度解析:架构、原理与应用实践
    • 机器学习TF-IDF算法详解
    • scikit-learn/sklearn学习|岭回归解读
    • AI 视频卫士:AI 无人机巡检,适配多元河道场景的治理利器
    • 网络基础与套接字的学习
    • canvas实现图片标注之Fabric.js从入门学习到实现labelImg矩形多边形标注工具【下】
    • 河北邢台数控滑台与机器人行走轨道的内在联系
    • 煤矿工地运煤卡车的4G远程视频监控解决方案
    • QT通过qputenv设置环境变量与使用(AI生成)
    • vue2中this.$createElement()在vue3中应该如何改造
    • 开闭原则代码示例
    • Spring Framework源码解析——BeanPostProcessor
    • 进程的理解
    • 无人机航拍数据集|第12期 无人机停车场车辆计数目标检测YOLO数据集1568张yolov11/yolov8/yolov5可训练
    • 数字图像处理4
    • Spring Framework源码解析——InitializingBean
    • 线程池ThreadPoolExecutor源码剖笔记
    • 对自己的 app 进行分析, 诊断,审视
    • pcl完成halcon3d中的下采样(按对角个数)