[Day 20 - React] 网页UI组件化 — React component

前情提要:在上一篇现在开始用框架写网页 — React,我们学习了如何在 React 使用 JSX 撰写 Element 呈现出网页页面,接下来就会带着大家将这些 React Element 抽离,建立 React 的核心 — Component,并且处理组件内部的资料。

建立 React component

直接利用上一篇文章的 Codesandbox React 专案,我们会实作做一个简单的计数器。在上篇文章的最後,提到 index.js 里面的 <App /> 就是一个 Component,组件的内容就实作在 app.js 里。直接修改 app.js 内部的 React Element,呈现出计数器的画面:

App.js

export default function App() {
  return (
    <div className="App">
      <h1>Member Score</h1>
      <div className="member">
        <h2>May</h2>
        <h3>0</h3>
        <button>Plus</button>
        <button>Minus</button>
      </div>
    </div>
  );
}

组件的内容被包裹在函式内部,这被称作是 Function Component。在 index.js 引入在别份程序码 export 的 Component 後,就会接收它所回传的 React Element 渲染在网页上。

接着可以将记录成员的资料和计数器的网页元素抽离,新增 Member.js ,拆离上面的 member 区块变成一个新的 Component。

Member.js

export default function Member() {
  return (
    <div className="member">
      <h2>May</h2>
      <h3>0</h3>
      <button>Plus</button>
      <button>Minus</button>
    </div>
  );
}

拆离 Component 并且将它 export 後,要做的事就是在 app.js 引入它。

import Member from "./Member";

export default function App() {
  return (
    <div className="App">
      <h1>Member Score</h1>
      <!-- 由使用者定义 component 的 element  -->
      <Member />
    </div>
  );
}

我们可以随意将网页内容划分成无数个 Component,不过仍然要遵守拆解的原则,让 Component 只会负责处理与该组件有关的事情。另外你还可以将 Component 拆成更小 Component,比如 Member 内的计数器,就能抽离成 Counter Component。

Counter.js

export default function Counter() {

  return (
    <div className="counter">
      <h3>0</h3>
      <button>Plus</button>
      <button>minus</button>
    </div>
  );
}

Member.js

import Counter from "./Counter";

export default function Member() {
  return (
    <div className="member">
      <h2>May</h2>
      <Counter />
    </div>
  );
}

透过 Prop 传递组件资料

介面组件化的优点之一就是提升重复使用性,比如现在想要有三位成员的分数资料,只要复制三个 <Member /> 组件,就可以呈现出同样的画面,但同时三个组件会是独立的,拥有各自的组件资料

App.js

export default function App() {
  return (
    <div className="App">
      <h1>Member Score</h1>
      <Member />
      <Member />
      <Member />
    </div>
  );
}

但问题是,现在三个 Component 的名字都是 May,我们希望能够显示成员各自的名字。React 就提供一个方法,可以将资料变成物件在 Component 间传递,这个物件就被称作「props」。举例来说,只要在 <Member /> 加上 name='名字' 属性,{name='名字'} 就会作为 props 传入到 Member Component 内。

App.js

export default function App() {
  return (
    <div className="App">
      <h1>Member Score</h1>
      <Member name='May'/>
      <Member name='Selina'/>
      <Member name='Julia'/>
    </div>
  );
}

分别设定好每个组件 props 的值,直接在 Member Component 接收 props 变数使用,就能显示出各自的名字。

Member.js

import Counter from "./Counter";

export default function Member(props) {
  return (
    <div className="member">
      <h2>props.name</h2>
      <Counter />
    </div>
  );
}

加入 Local State 到组件

计数器的部分,两个 Button 可以控制分数的加减,并且要让Component 能够记录并更新分数,我们需要将分数存放到 State 中,当 render() 内部的 State 值更新,React 就会相对地更新网页内容。

要在 Function Component 使用 State,会使用到 Hook 功能 useState,它会回传目前 state 数值,和可以让你更新 State 的 Function,同时要设定初始值。

Counter.js

import { useState } from "react";

export default function Counter() {
  //宣告一个 state 变数 score,初始值为 0
  const [score, setScore] = useState(0);

  return (
    <div className="Counter">
      <h3>{score}</h3>
      ...
    </div>
  );
}

现在要利用 useState 的 State Function,试着让 State 随着我们的输入来更新。在两个 Button 分别加上 Click 事件,按下 Plus 就让计数器的值加一,按下 Minus 就减一:

Counter.js

export default function Counter() {
  ...
  return (
    <div className="Counter">
      ...
      <button onClick={() => setScore(score + 1)}>Plus</button>
      <button onClick={() => setScore(score - 1)}>minus</button>
    </div>
  );
}

完成後试着按一按每个成员的计分器,你可以发现每个 Component 就能拥有自己的 State,分别成功记录每位成员的分数。


小结

大致了解 React 最重要的核心 — Component,我们现在可以自定义网页元件,并在组件内控制资料的处理。但 React 能做到的不会只有可将网页介面拆成独立的组件、提升重用性,下一个章节就再来探讨 React 其他更便利的功能,包括条件 Render、生成列表,以及如何提升 Component 的资料层级。

范例程序码

如果文章中有错误的地方,要麻烦各位大大不吝赐教;喜欢的话,也要记得帮我按赞订阅喔❤️

参考资料


<<:  Day18 page fault, LRU, second chance

>>:  Day 18 Rails MVC

Java学习之路05---运算子

架构图 前言 表达式是程序进行算术运算中的表示方式,我们可以简单地把表达式拆解为表达式 = 运算子 ...

Unity自主学习(十一):认识Unity介面(2)

今天研究了一下主要的区块"场景编辑区"的操作方式 在一开始还没有添加任何东西时,...

Day 0x1A UVa10931 Parity

Virtual Judge ZeroJudge 题意 输入整数 I,输出二进位表示法与 parit...

JS 24 - 请求支援前,要先发送请求!

大家好! 发送请求时,各位有没有多写好几行程序码的经验呢? 今天就是要简化如此复杂的动作。 我们进入...

[Day24] Rocket Web 框架 (Part 1)

今天要讲的是 Rocket 那我先简述一下什麽是 Rocket Rocket 是一个致力於实现 快速...