【React】01-React 入门到放弃系列

news/2024/7/15 18:42:31 标签: react.js, arcgis, 前端

01-React 入门

  • 背景
  • 入门
    • 学生成绩录入的表单
  • 小结


背景

由于捣鼓一些项目需要用到React,找了一些文档入门实践了一番。本篇文章以一个学生成绩录入的表单为例子,记录React 入门的一些基础操作。

入门

该操作的前提是本地安装了NodeJS环境。根据官网给的例子,我们使用如下命令初始化项目

npx create-react-app react4j

目录结构如下:

react-practice
├── react4j
│   ├── public
│   │   ├── favicon.ico
│   │   ├── index.html
│   │   ├── logo192.png
│   │   ├── logo512.png
│   │   ├── manifest.json
│   │   └── robots.txt
│   ├── src
│   │   ├── App.css
│   │   ├── App.js
│   │   ├── App.test.js
│   │   ├── index.css
│   │   ├── index.js
│   │   ├── logo.svg
│   │   ├── reportWebVitals.js
│   │   └── setupTests.js
│   ├── README.md
│   ├── package-lock.json
│   ├── package.json
└── list.md

● 目录 src :React 应用源码存放的目录。
● 目录 public 包含了开发应用时浏览器会读取的文件,其中最重要的就是 index.html。React 将目录 src 中的代码嵌入这个文件,从而浏览器才能运行此文件。
● 文件 package.json 包含了 Node.js/npm 为了建立该应用程序所管理着的文件信息
● manifest.json 文件定义了应用的名称、简称、图标、启动 URL、显示模式、主题颜色和背景色

启动项目,这里我们可以预览:

npm start

关于 index.html,是项目的主页面,这里只定义一个id为root的标签:

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      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>

关于index.js,这里引入我们的App组件,App组件定义在App.js文件里。

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  // <React.StrictMode>
  //   <App />
  // </React.StrictMode>
  <App subject="Clarice" />
);

关于App.js,由三部分组成:顶部的 import 语句,中间的 App 组件,以及底部的 export 语句。通过export ,我们可以在项目入口的 index.js文件里用 <APP /> 标签直接使用该组件。

这里的函数命名 App 也是React 特殊的命名方式,它使用帕斯卡命名法,如“HelloWorld”,来帮助用户辨认一个 JSX 元素是 React 组件而非普通的 HTML 标签。如果你将函数名“App”改为“app”,你的浏览器会显示错误。

import React from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer">
          Learn React
        </a>
      </header>
    </div>
  );
}
export default App;


学生成绩录入的表单

  1. 删除多余的文件 App.test.js App.css logo.svg serviceWorker.js setupTests.js
  2. 在App.js 编写UI,这里存储数据先暂时用localStorage存储录入的数据。
import React, { useState, useEffect } from 'react';


const ScoreTable = () => {
  console.log(111)
  const [scores, setScores] = useState([]);
  const [studentName, setStudentName] = useState('');
  const [studentScore, setStudentScore] = useState('');

  useEffect(() => {
    // 从localStorage中读取数据,并设置为初始state值
    const storedScores = localStorage.getItem('scores');
    if (storedScores) {
      setScores(JSON.parse(storedScores));
    }
  }, []);

  useEffect(() => {
    // 每次scores更新后,将数据保存到localStorage中
    localStorage.setItem('scores', JSON.stringify(scores));
  }, [scores]);
  
  const handleNameChange = (e) => {
    setStudentName(e.target.value);
  };

  const handleScoreChange = (e) => {
    setStudentScore(e.target.value);
  };

  const handleAddScore = () => {
    if (studentName && studentScore) {
      const newScore = {
        name: studentName,
        score: studentScore
      };
      setScores([...scores, newScore]);
      setStudentName('');
      setStudentScore('');
    }
  };


  return (
    <div className="todoapp stack-large">
      <h1>学生成绩录入</h1>
      <form>
        <label htmlFor="new-todo-input" className="label__lg">
          学生姓名:
        </label>
        <input
          type="text"
          id="new-todo-input"
          className="input input__lg"
          name="text"
          value={studentName}
          autoComplete="off"
          onChange={handleNameChange}
        />
        <label htmlFor="new-todo-input" className="label__lg">
          学生成绩:
        </label>

        <input
          type="text"
          id="new-todo-input"
          className="input input__lg"
          name="text"
          value={studentScore}
          autoComplete="off"
          onChange={handleScoreChange}
        />

        <button type="submit" className="btn btn__primary btn__lg" onClick={handleAddScore}>
          新增
        </button>
      </form>

      <h2 id="list-heading">名单列表</h2>
      <table>
        <thead>
          <tr>
            <th>姓名</th>
            <th>成绩</th>
          </tr>
        </thead>
        <tbody>
          {scores.map((score, index) => (
            <tr key={index}>
              <td>{score.name}</td>
              <td>{score.score}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}


function App(props) {
  console.log(props)

  return (
    <ScoreTable />
  );
}

export default App;

  1. 编写CSS样式,可以直接copy如下的CSS样式,取代原来的index.css文件:
/* RESETS */
*,
*::before,
*::after {
  box-sizing: border-box;
}
*:focus {
  outline: 3px dashed #228bec;
  outline-offset: 0;
}
html {
  font: 62.5% / 1.15 sans-serif;
}
h1,
h2 {
  margin-bottom: 0;
}
ul {
  list-style: none;
  padding: 0;
}
button {
  border: none;
  margin: 0;
  padding: 0;
  width: auto;
  overflow: visible;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: normal;
  -webkit-font-smoothing: inherit;
  -moz-osx-font-smoothing: inherit;
  -webkit-appearance: none;
}
button::-moz-focus-inner {
  border: 0;
}
button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-size: 100%;
  line-height: 1.15;
  margin: 0;
}
button,
input {
  overflow: visible;
}
input[type="text"] {
  border-radius: 0;
}
body {
  width: 100%;
  max-width: 68rem;
  margin: 0 auto;
  font:
    1.6rem/1.25 Arial,
    sans-serif;
  background-color: #f5f5f5;
  color: #4d4d4d;
}
@media screen and (min-width: 620px) {
  body {
    font-size: 1.9rem;
    line-height: 1.31579;
  }
}
/*END RESETS*/
/* GLOBAL STYLES */
.form-group > input[type="text"] {
  display: inline-block;
  margin-top: 0.4rem;
}
.btn {
  padding: 2px;
  margin-left: 5px;
  border: 0.2rem solid #4d4d4d;
  cursor: pointer;
  text-transform: capitalize;
}
.btn.toggle-btn {
  border-width: 1px;
  border-color: #d3d3d3;
}
.btn.toggle-btn[aria-pressed="true"] {
  text-decoration: underline;
  border-color: #4d4d4d;
}
.btn__danger {
  color: #fff;
  background-color: #ca3c3c;
  border-color: #bd2130;
}
.btn__filter {
  border-color: lightgrey;
}
.btn__primary {
  color: #fff;
  background-color: #000;
}
.btn-group {
  display: flex;
  justify-content: space-between;
}
.btn-group > * {
  flex: 1 1 49%;
}
.btn-group > * + * {
  margin-left: 0.8rem;
}

.visually-hidden {
  position: absolute !important;
  height: 1px;
  width: 1px;
  overflow: hidden;
  clip: rect(1px 1px 1px 1px);
  clip: rect(1px, 1px, 1px, 1px);
  white-space: nowrap;
}
[class*="stack"] > * {
  margin-top: 0;
  margin-bottom: 0;
}
.stack-small > * + * {
  margin-top: 1.25rem;
}
.stack-large > * + * {
  margin-top: 2.5rem;
}
@media screen and (min-width: 550px) {
  .stack-small > * + * {
    margin-top: 1.4rem;
  }
  .stack-large > * + * {
    margin-top: 2.8rem;
  }
}
.stack-exception {
  margin-top: 1.2rem;
}
/* END GLOBAL STYLES */
.todoapp {
  background: #fff;
  margin: 2rem 0 4rem 0;
  padding: 1rem;
  position: relative;
  box-shadow:
    0 2px 4px 0 rgba(0, 0, 0, 0.2),
    0 2.5rem 5rem 0 rgba(0, 0, 0, 0.1);
}
@media screen and (min-width: 550px) {
  .todoapp {
    padding: 4rem;
  }
}
.todoapp > * {
  max-width: 50rem;
  margin-left: auto;
  margin-right: auto;
}
.todoapp > form {
  max-width: 100%;
}
.todoapp > h1 {
  display: block;
  max-width: 100%;
  text-align: center;
  margin: 0;
  margin-bottom: 1rem;
}
.label__lg {
  display: inline-block;
  line-height: 1.01567;
  font-weight: 300;
  padding: 0.8rem;
  margin-bottom: 1rem;
  text-align: center;
}
.input__lg {
  padding: 1px;
  border: 2px solid #000;
}
.input__lg:focus {
  border-color: #4d4d4d;
  box-shadow: inset 0 0 0 2px;
}
[class*="__lg"] {
  display: inline-block;

  font-size: 14px;
}
[class*="__lg"]:not(:last-child) {
  font-size: 14px;
}
@media screen and (min-width: 620px) {
  [class*="__lg"] {
    font-size: 14px;
  }
}
.filters {
  width: 100%;
  margin: unset auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  font-family: Arial, sans-serif;
  color: #333;
}

table th, table td {
  padding: 8px;
  text-align: left;
  border-bottom: 1px solid #ddd;
}

table th {
  background-color: #f2f2f2;
  font-weight: bold;
}

table tr:nth-child(even) {
  background-color: #f9f9f9;
}

table tr:hover {
  background-color: #e6e6e6;
  cursor: pointer;
}

input[type="text"] {
  padding: 8px;
  border: 1px solid #ddd;
  border-radius: 4px;
}
  1. npm start 预览:

在这里插入图片描述


小结

  1. 本人实践下来,跟原来HTML + JavaScript 最明显的区别就是,React把UI封装到一个个JS函数里面去了。这跟它官网的描述也挺相符的, 通过使用组件最大程度地减少开发人员构建 UI 时发生的错误。。

  2. React 与 JavaScript 的最大区别在于 JSX 语法的使用上。JSX 是在 JavaScript 语法上的拓展,因此类似于 HTML 的代码可以和 JSX 共存。更多资料可以看看官方文档。


http://www.niftyadmin.cn/n/5308812.html

相关文章

K8S----PVPVCSC

一、简介 1、PV(persistent volume)–持久卷 PV是集群中的一块存储,可以由管理员事先静态(static)制备, 也可以使用存储类(Storage Class)来动态(dynamic)制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件(volume p…

客服系统或网站多语言的实现方式

客服系统经常用于海外业务&#xff0c;或跨境电商独立站&#xff0c;所以界面上需要支持多语言。 static/js/functions.js 中的checkLang()函数是检测函数。 首先&#xff0c;从URL参数 “lang” 中获取语言&#xff0c;如果存在且在支持的语言列表中&#xff0c;则返回该语言…

【STM32】STM32学习笔记-DMA数据转运+AD多通道(24)

00. 目录 文章目录 00. 目录01. DMA简介02. DMA相关API2.1 DMA_Init2.2 DMA_InitTypeDef2.3 DMA_Cmd2.4 DMA_SetCurrDataCounter2.5 DMA_GetFlagStatus2.6 DMA_ClearFlag 03. DMA数据单通道接线图04. DMA数据单通道示例05. DMA数据多通道接线图06. DMA数据多通道示例一07. DMA数…

Decontam与SCRUB:安装与使用

Decontam安装 GitHub - benjjneb/decontam: Simple statistical identification and removal of contaminants in marker-gene and metagenomics sequencing data 准备Rstudio if (!requireNamespace("BiocManager", quietly TRUE))install.packages("BiocM…

Python用正则匹配来统计已写源码行数的示例(Crossin教室实例27)

一、问题描述&#xff1a; 码农经常会被问到&#xff0c;一共写过多少行代码&#xff1f;现在&#xff0c;给定一个包含py 文件的目录&#xff0c;统计该目录中所有源码文件的总行数&#xff0c;并分别列出注释行、空行与有效代码的行数。请注意&#xff0c;为了简化问题&…

5.云原生安全之kubesphere应用网关配置域名TLS证书

文章目录 cloudflare配置使用cloudflare托管域名获取cloudflare API Token在cloudflare中配置SSL/TLS kubesphere使用cert-manager申请cloudflare证书安装证书管理器创建Secret资源创建cluster-issuer.yaml创建cert.yaml申请证书已经查看申请状态 部署harbor并配置ingress使用证…

前端会造成内存泄漏的操作有哪些?页面卡住的原因

如果你发现前端页面卡住了&#xff0c;打开开发者工具也很卡&#xff0c;刷新页面也无效、或者关闭 tab页也很费劲&#xff0c;多半是有内存泄漏。 内存泄漏其实就是浏览器的内存被占用很多&#xff0c;导致页面奔溃。 以下是一些常见的引起内存泄漏的操作&#xff1a; 未正确…

FlinkSQL处理Canal-JSON数据

背景信息 Canal是一个CDC&#xff08;ChangeLog Data Capture&#xff0c;变更日志数据捕获&#xff09;工具&#xff0c;可以实时地将MySQL变更传输到其他系统。Canal为变更日志提供了统一的数据格式&#xff0c;并支持使用JSON或protobuf序列化消息&#xff08;Canal默认使用…