React 项目:计算器

2023-10-29

本教程专注于 React 部分,故对 css 及 js 不做过多解释

项目地址:yuzheng14/calculator (github.com)

分析原型

组件结构

应用中一共包含 4 个组件

  1. APP:整个应用的整体
  2. Display:展示输入数据及计算结果
  3. ButtonPanel:按键区
  4. Button:每一个按键

创建静态版本

使用 create-react-app 创建一个空项目

npx create-react-app <name> && cd <name>

删除 srcpublic 目录下的所有文件

初始项目结构

rm -f src/* public/*

按照目录结构创建所需文件

js文件项目结构

创建首页模板

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
  <meta name="viewport" content="width=device-width, user-scalable=no" />
  <meta name="theme-color" content="#000000" />
  <meta name="description" content="Calculator" />
  <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
  <title>React Calculator</title>
</head>

<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>
  <a class="github-fork-ribbon left-top" href="https://github.com/yuzheng14" data-ribbon="See me on Github" title="See me on Github">
    See me on Github
  </a>
  <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
</body>

</html>

开始自底向上构建组件,首先是 Button 组件:

import PropTypes from 'prop-types';

export default function Button(props) {
    const className = `component-button ${props.orange ? 'orange' : ''
        } ${props.wide ? 'wide' : ''
        }`;

    return (
        <div className={className}>
            <button>{props.name}</button>
        </div>
    )

}

Button.propTypes = {
    name: PropTypes.string,
    orange: PropTypes.bool,
    wide: PropTypes.bool,
}

该组件获取从父组件中获取 wide 和 orange 属性用于指定样式

ButtonPanel 组件:

import Button from "./Button";

export default function ButtonPanel(props) {
    return(
        <div className="component-button-panel">
            <div>
                <Button name="AC" />
                <Button name="+/-" />
                <Button name="%"/>
                <Button name="÷"  orange/>
            </div>
            <div>
                <Button name="7" />
                <Button name="8" />
                <Button name="9"/>
                <Button name="×"  orange/>
            </div>
            <div>
                <Button name="4" />
                <Button name="5" />
                <Button name="6"/>
                <Button name="-"  orange/>
            </div>
            <div>
                <Button name="1" />
                <Button name="2" />
                <Button name="3"/>
                <Button name="+"  orange/>
            </div>
            <div>
                <Button name="0"  wide/>
                <Button name="." />
                <Button name="="  orange/>
            </div>
        </div>
    )
}

该组件组合所有按键,通过 orange 和 wide 属性制定按键样式

Display 组件:

import PropTyes from 'prop-types';

export default function Display(props){
    return(
        <div className="component-display">
            <div>{props.value}</div>
        </div>
    )
}

Display.propTypes={
    value:PropTyes.string,
}

该组件接收要显示的值并渲染

App 组件:

import Display from "./Display";
import ButtonPanel from "./ButtonPanel";

export default function App() {
    return (
        <div className="component-app">
            <Display value={} />
            <ButtonPanel />
        </div>
    )
}

该组件组合 DisplayButtonPanel 组件

index.js 文件:

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './component/App';
import 'github-fork-ribbon-css/gh-fork-ribbon.css';

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

该文件用于将 App 组件渲染到网页,对应仓库中 v0.1.0 的 tag,写好后页面是这样

在这里插入图片描述

从仓库中导入样式,目录为

src/index.css
src/styles/*

并将各个 css 文件引入对应的 js 文件中,写好后页面变成

在这里插入图片描述

静态页面代码完成,对应仓库中 v0.1.1 的 tag,接下来该开始思考交互部分了

确定 UI state 的最小(且完整)表示及放置位置

为了正确构建应用,我们应该找出应用所需的 state,以及放置的位置。本应用中需要组件中传递变量的过程为按下按键后,更新状态,传递给显示组件,取最小公共父组件,则为 App 组件。根据算式最少需要两个运算数和一个运算符,可知最少需要三个状态。修改 App 组件为类组件以保存状态,将状态添加到 App 组件中。

...
export default class App extends Component{
    constructor(props){
        super(props);
        // total 用于存放第一个运算数及计算结果
        // next 用于存放第二个运算数
        // operation 用于存放运算符
        this.state={
            total:null,
            next:null,
            operation:null,
        };
    }

	render(){
	...
    		   // 将状态计算得到要显示的数字传入组件中
                <Display value={this.state.next||this.state.total||"0"}/>
     ...
}

添加反向数据流

到目前为止,我们已经借助自上而下传递的 props 和 state 渲染了一个应用。现在,我们将尝试让数据反向传递:Button 组件–> App 组件。

我们要实现的功能是:当用户按下按键时,我们需要改变 state 来反映用户的当前输入,并传入显示页面进行显示。由于 state 只能由拥有他们的组件进行更改,所以我们要在 App 组件中添加一个用于触发 state 改变的回调函数向下传递。我们可以使用按钮的 onClick 事件来监听用户的输入,并通知回调函数。然后该回调函数将调用 setState(),从而更新应用。

从仓库中导入需要使用的 js 文件

src/logic/*

修改 React 代码

// App.js
export default class App extends Component {
    ...

    handleClick = buttonName => {
        this.setState(calculate(this.state, buttonName))
    }

    render() {
                ...
                <ButtonPanel clickHandler={this.handleClick} />
                ...
    }
}
// ButtonPanel.js
export default function ButtonPanel(props) {
    return(
        ...
            <div>
                <Button name="AC" clickHandler={props.clickHandler}/>
                <Button name="+/-" clickHandler={props.clickHandler}/>
                <Button name="%"clickHandler={props.clickHandler}/>
                <Button name="÷" clickHandler={props.clickHandler} orange/>
            </div>
            <div>
                <Button name="7" clickHandler={props.clickHandler}/>
                <Button name="8" clickHandler={props.clickHandler}/>
                <Button name="9"clickHandler={props.clickHandler}/>
                <Button name="×" clickHandler={props.clickHandler} orange/>
            </div>
            <div>
                <Button name="4" clickHandler={props.clickHandler}/>
                <Button name="5" clickHandler={props.clickHandler}/>
                <Button name="6"clickHandler={props.clickHandler}/>
                <Button name="-" clickHandler={props.clickHandler} orange/>
            </div>
            <div>
                <Button name="1" clickHandler={props.clickHandler}/>
                <Button name="2" clickHandler={props.clickHandler}/>
                <Button name="3"clickHandler={props.clickHandler}/>
                <Button name="+" clickHandler={props.clickHandler} orange/>
            </div>
            <div>
                <Button name="0" clickHandler={props.clickHandler} wide/>
                <Button name="." clickHandler={props.clickHandler}/>
                <Button name="=" clickHandler={props.clickHandler} orange/>
            </div>
        ...
    )
}
// Button.js
export default function Button(props) {
    return (
        <div className={className}>
            <button onClick={() => props.clickHandler(props.name)}>{props.name}</button>
        </div>
    )
}

此时整个应用已经完全写好,可以 npm start 启动应用了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React 项目:计算器 的相关文章

  • 循环遍历数组并删除项目,而不中断 for 循环

    我有以下 for 循环 当我使用splice 要删除一个项目 我发现 秒 未定义 我可以检查它是否未定义 但我觉得可能有一种更优雅的方法来做到这一点 我们的愿望是简单地删除一个项目并继续 for i 0 len Auction auctio
  • 如何在javascript中动态向对象数组添加值?

    这是一个对象数组 var data label 1 value 12 label 1 value 12 label 1 value 12 label 1 value 12 我如何动态地为这些添加值 我尝试了以下代码但没有成功 var lab
  • appendChild 错误:无法在层次结构中的指定点插入节点

    There is an error with the function appendChild Node cannot be inserted at the specified point in the hierarchy JS var a
  • 返回上一页

    我正在使用表格来 评价 页面 此表单将数据 发布 到其他地方的 php 脚本 我只是想在处理表单后显示一个链接 这将使用户返回到上一页 我可以在 php 脚本中使用 javascript 来执行此操作吗 GF 您可以使用链接来调用histo
  • jQuery 可以操作插入的元素吗?

    我是 jQuery 的新手 我认为 jQuery 可以操作由代码添加的元素是合理的 但我发现现在还不能 function addVideo click function publisher append div div
  • 调用类实例方法 onclick javascript

    我有一个 javascript 文件 其中包含包含方法函数的类 我想知道如何从 onClick 事件调用类实例方法 function MyClass this instanceData Display Me this DisplayData
  • 在 React 中使用 .less 文件

    我正在尝试将 less 文件与极简主义 React 应用程序一起使用 使用创建反应应用程序 我已经添加less and less loader to my 包 json以及我的模块规则webpack config js文件 然而 类引用并未
  • 如何在 jQuery 中将标题转换为 URL slug?

    我正在 CodeIgniter 中开发一个应用程序 我试图在表单上创建一个字段来动态生成URL slug 我想做的是删除标点符号 将其转换为小写 然后用连字符替换空格 例如 Shane s Rib Shack 将变成 shanes rib
  • 仅在 Chrome 上我收到此错误:Uncaught TypeError: Illegal constructor [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 当我在 Chrome 上加载 jQuery 时 我会收到此错误 Uncaught TypeError Illegal constr
  • “require(...)”是常见的 JavaScript 模式还是库函数?

    我通常发现这是 node js 脚本 模块以及 phantomJS casperJS 等中的第一行 我很好奇 这是否是服务器端 javascript SSJS 的常见模式 类似于 include在 C C 中或import在 Java 中
  • 如何在 JavaScript 中将变量的内容写入文件[重复]

    这个问题在这里已经有答案了 可能的重复 firefox 如何启用本地 JavaScript 来读取 写入我的 PC 上的文件 https stackoverflow com questions 2846045 firefox how to
  • 为什么函数声明在不同浏览器中的处理方式不同?

    虽然我在谷歌中找不到对此的引用 但我熟悉这样一个事实 在 javascript 中 全局函数声明在执行任何代码之前都会被解释 换句话说 这工作得很好 f function f 但是 我注意到 chrome 和 firefox 对全局函数声明
  • 修改 Twitter 帖子上可编辑 Div 的内容

    我正在编写一个 chrome 扩展 它可以帮助用户在 Twitter 上输入内容 当在 twitter 上写推文时 twitter 会打开一个可编辑的 div 容器 当用户输入内容时 twitter 大概正在使用某些网络框架 会生成子 di
  • 如何包装内在组件,保留大部分 Props?

    我想用我自己的 React 功能组件包装一个标准按钮 但我希望新组件的用户能够设置 几乎所有底层按钮的道具 当然 我想保持正确的打字 所以如果 WrappedButton 包含一个button then
  • Socket IO 服务器到服务器

    服务器是否可以使用 Socket IO 连接到另一个服务器并被视为客户端 并让它加入房间 接收 io sockets in lobby emit 和更多 第一个服务器也在监听连接 消息 嘿 Brad 下面是我的完整 js 应用程序 供参考
  • JSONP 使用 JQuery 从 HTTPS 协议获取 JSON

    我正在尝试获取从 https 安全站点发送的 JSON 客户端希望不要使用任何服务器端语言 全部都是 Javascript 我读到 当使用 Jquery 中的 ajax 函数时 我必须使用 JSONP 才能从安全站点加载 JSON 我的第一
  • 在 Nodejs 中,如何停止 FOR 循环直到 MongoDB 调用返回

    我正在研究下面的代码片段 我有一个名为 stuObjList 的 JSON 对象数组 我想循环遍历数组以查找具有特定标志集的特定 JSON 对象 然后进行数据库调用以检索更多数据 当然 FOR 循环不会等待数据库调用返回并到达 j leng
  • 标记(Markdown)+ Mermaid(流程图和图表)

    努力去争取 美人鱼 https github com knsv mermaid https github com knsv mermaid跟 共事 标记 https github com chjj marked https github c
  • Vue-Router 抽象父路由

    我正在尝试将当前网站迁移到 vuejs 站点地图必须是 login signup password reset browse search dozens of other routes 由于其中一些路线共享大量 fx 因此我将它们设为父路线
  • 如何通过点击复制 folium 地图上的标记位置?

    I am able to print the location of a given marker on the map using folium plugins MousePosition class GeoMap def update

随机推荐

  • 人脸修复祛马赛克算法CodeFormer——C++与Python模型部署

    一 人脸修复算法 1 算法简介 CodeFormer是一种基于AI技术深度学习的人脸复原模型 由南洋理工大学和商汤科技联合研究中心联合开发 它能够接收模糊或马赛克图像作为输入 并生成更清晰的原始图像 算法源码地址 https github
  • Qt5 项目文件.pro参数详解

    qmake的概念 qmake是用来为不同的平台的开发项目创建makefile的一个工具 qmake简化了makefile的生成 因此创建一个makefile只需要几行信息的文件 qmake可以供任何一个软件项目使用 而不用管他是不是使用Qt
  • C/C++Java生成指定长度随机字符串的三种方法

    学习 实验记录 也是方便自己以后查找 目录 两种实现思路 第一种实现思路 随机数转char 第二种思路 随机数取字符 C语言 使用char数组 C语言 使用char C 使用string类 Java通过字符数组或字符串方式 两种实现思路 C
  • Android OnTouchListener自定义 onTouch完全解析

    做android开发对touch事件是要清晰明了的 如果心存疑问 那么本博客 可以帮你清晰的屡清楚源码是如果实现 onLongClickListener onDoubleClickListener onClickListener 并且再次基
  • Python遍历多个列表:ValueError: too many values to unpack (expected 2)

    项目场景 在进行列表遍历的时候 希望同时遍历多个列表 问题描述 在使用循环遍历两个列表时 希望x y各自获取到数组a b里全部的元素 却产生了意料之外的报错 ValueError too many values to unpack expe
  • vue-introjs实现网站引导功能

    文章目录 说明 效果展示 静态 动态演示 相关技术 intro js 的一分钟入门说明 在 vue 项目中使用 intro js 安装 配置 使用 一些问题 只首次进入的时候显示引导 如果是 v for 循环出来的元素 我们咋显示引导内容呢
  • stm32f407 6个串口dma_STM32实例DMA 实验

    在前面我们提到过 DMA 这一章我们就来学习 STM32F1 的DMA 使 用 要实现的功能是 通过 K UP 按键控制 DMA 串口 1 数据的传送 在传送过程中让 D2 指示灯不断闪烁 直到数据传送完成 D1 指示灯闪烁提示系统正常运行
  • 华为od机试 python 计算快递主站点

    题目 题目背景 一个快递公司 有一些站点之间可以直接传送快递 如果站点A可以传送给站点B 同时站点B又可以传送给站点C 那么其实站点A也可以直接或间接地传送给站点C 现在的问题是 给定一些站点以及他们之间是否可以直接传送快递的信息 为了确保
  • QMessageBox的使用(二)

    参考博客 以下内容摘抄以下链接大神博客 https blog csdn net zjx1230 article details 83715421 QMessageBox warning this Search String Please e
  • python的launcher用法知识点总结

    更多编程教程请到 菜鸟教程 https www piaodoo com python launcher是适用于 Windows 的 Python 启动器 可帮助您定位和执行不同的 Python 版本 它允许脚本 或命令行 为特定的 Pyth
  • Idea 生成模板代码(Demo)

    1 在html文件中复制需要生成模板的代码 如下图选中部分 ctrl c 2 点击 File gt Settings 如下图 3 选择 Editor gt Live Template 点击右边的 然后点击 1 Live Template 如
  • 【Yarn】Yarn ApplicationMasterLauncher的工作机制

    文章目录 1 概述 2 源码 2 1 类变量 2 2 构造方法 2 4 serviceInit 2 5 serviceStart 2 6 LauncherThread 2 7 launch事件 2 8 AMLauncher的run 1 概述
  • 前端框架Vue(5)——Vue + Echarts (数据可视化)

    Echarts 是数据可视化中佼佼者 推荐大家可以玩一玩 非常实用 如果第一次接触Echarts的同学 这边有我以前写过的一篇入门 浅谈Echarts3 0 Vue Echarts 现附上代码
  • 数据结构作业:实现链表的基本操作

    数据结构作业 实现链表的基本操作 链表是一种常见的数据结构 它由一系列节点组成 每个节点包含数据和指向下一个节点的指针 本文将介绍链表的基本操作 包括创建链表 插入节点 删除节点以及遍历链表 首先 我们需要定义链表节点的结构体 节点包含一个
  • signature=31a231fa44057e3d64bcbe8f86676d0e,typescript-definitions

    THIS IS AN AUTOGENERATED FILE DO NOT EDIT THIS FILE DIRECTLY yarn lockfile v1 continuous auth client 1 1 0 version 1 2 3
  • 2020-04-08

    查看有关计算机的基本信息 1 右键点击 计算机 的 属性 就能看到这台电脑的基本信息了
  • Android Platform 3.0 SDK和Eclipse ADT安装记录(最初版本,纪念用)

    注意 此文非常非常地过时 只是用于个人回想 请参看 二 以后的笔记 20110926 注意 此文由于结构过于混乱且内容过时 将会被删除 用新的学习日记取代 如果我有时间的话 注 我只是为了学习简单的Android编程和模拟 所以没有考虑SD
  • 图示CORDIC算法

    目录 简介 原理 硬件实现 简介 CORDIC Coordinate Rotation Digital Computer 坐标旋转数字计算方法 应用 计算三角函数 cos sin tan 或者计算旋转角 原理 问题 在下图中 C点的坐标是
  • 阿里云教程安装WordPress没有 安装新插件 及 主题 的按钮

    表象 在插件页面和主题页面没有Add New的按钮 经过一番百度后 主要分为两派 文件权限问题 your wordpress site folder如果按照阿里云教程 该地址为 var www html wp blog 解决方案 chown
  • React 项目:计算器

    本教程专注于 React 部分 故对 css 及 js 不做过多解释 项目地址 yuzheng14 calculator github com 分析原型 应用中一共包含 4 个组件 APP 整个应用的整体 Display 展示输入数据及计算