[Day21] 在 Codecademy 学 React ~ What's this? This is "this"! 之 this.props 篇

前言

今天要来讲 this.props 了,
但在那之前我发现我还没讲过 this XD
就跟学英文一样第一句要学的是 "This is a pen.",
那麽要开始学 props 之前我们当然也要来学 This is "this" 罗XD
那就让我们开始吧!Codecademy - this.props

本日正文

What's "this"

this 是 React 很常使用的语法,
(虽然我现在比较常用的写法不会用到 this 就是了XD")
在 Codecademy 一开始用了一个范例,
这边也让大家猜一下这边的 this 指的是谁:

class IceCreamGuy extends React.Component {
  get food() {
    return 'ice cream';
  }
 
  render() {
    return <h1>I like {this.food}.</h1>;
  }
}

答案就是 IceCreamGuy,
Codecademy 上的说明是这样的:

The simple answer is that this refers to an instance of IceCreamGuy.
The less simple answer is that this refers to the object on which this‘s enclosing method, in this case .render(), is called.

简单来说 this 是指 IceCreamGuy 的实体,
更简单的答案是 this 指向将 this 封闭的 method (render),其所属的物件上(render 属於 IceCreamGuy)

但老实说 this 我也不太晓得怎麽解释比较好,
所以这边就直接引 Codecademy 的说明,
Codecademy 在这边也有附一篇文章让大家更了解 this,
https://dmitripavlutin.com/gentle-explanation-of-this-in-javascript/
总之我个人先把 this 当作是当下其所属的容器(?

另外有找到卡斯伯老师关於 this 的说明文章,大家可以参考XD

this.props

上面对 this 有初步概念後,
就直接来讲 this.props 吧!
props 是指 properties,
所以 this.props 顾名思义就是目前这个容器(component)的属性,
例如一个水果会有名字、颜色、价格等属性。

那麽我先在 Fruits.js 宣告一个 Fruit 的 class,
里面分别用 this.props 取得三个属性:name, color, price,
像这样:

import React from "react";

export class Fruit extends React.Component {
  render() {
    return (
      <div>
        <h1>这是一个{this.props.name}</h1>
        <h1>颜色:{this.props.color}</h1>
        <h1>价格:{this.props.price}元</h1>
      </div>
    );
  }
}

而我在主页面 App.js 引入 Fruits.js 的 Fruit class,
并在 <Fruit> 的标签里分别设定它 name, color, price 的值,

<Fruit name="苹果" color="青绿色" price="100" />

像这样:

import { Fruit } from "./Fruits.js";

export default function App() {
  return (
    <div className="App">
      <Fruit name="苹果" color="青绿色" price="100" />
    </div>
  );
}

https://ithelp.ithome.com.tw/upload/images/20210923/201298733NkAs6eVts.png

然後就可以看到画面出现刚刚上面所设定的那些值。
再回过头看一下 Fruits.js 的这句:{this.props.name}
这边的 this 是指 Fruit,所以这意思是我要取用 Fruit 中 name 属性的值。

因此在 App.js 实际放了 <Fruit> 的 component,
<Fruit> 设定 name 属性,值为"苹果"。
<Fruit name="苹果">
这样 {this.props.name} 就会去找到 <Fruit> name 被设定的值,
并将结果渲染在页面上,
<h1>这是一个{this.props.name}</h1>
因此这样就会出现 这是一个苹果 的内容。

而这边属性都可以自订~

this.props 的 Event Handler

除了上述的自订属性之外,Event Handler 也可以被当成一种属性,
因此我也可以写 {this.props.onClick} 去取得属性 onClick 里面的值。

例如我现在 Button.js 宣告一个 Button 的 class,

import React from "react";

export class Button extends React.Component {
  render() {
    return <button onClick={this.props.onClick}>点我购买!</button>;
  }
}

再来在 Talker.js 宣告一个 Talker 的 class,
里面宣告一个 handleClick 的 函数,

handleClick() {
    let speech = "";
    for (let i = 0; i < 500; i++) {
      speech += "金额不足";
    }
    alert(speech);
}

以及放入 <Button> 的 component,
并给它 onClick 属性,值指向 {this.handleClick}

render() {
    return <Button onClick={this.handleClick} />;
}

先让大家看成果:

说明:
在 Button.js <button onClick={this.props.onClick}>
onClick 会指向 <Talker><Button> onClick 属性的值,
<Talker><Button> onClick 属性的值又被指向 {this.handleClick}
所以最後指向的是在 Talker.js 里面的 handleClick 函数,
因此上面点击按钮才会出现警告跳窗。

这边用图示应该会比较好懂一点:
https://ithelp.ithome.com.tw/upload/images/20210923/201298733B4b4zPQe4.png

this.props 的 children

每个 component 都会有 children 的属性,
this.props.children 就是指该 component 里面包的所有东西。

例如我在原本 App.js <Talker /> 的地方扩写成这样:

<Talker>
    <p>之後将会上架更多水果,敬请期待</p>
</Talker>

但你发现没有任何变化,
所以这时候我们在 Talker.js 将原本 render 的地方扩写成这样:

render() {
    return (
      <div>
        <Button onClick={this.handleClick} />
        {this.props.children}
      </div>
    );
}

https://ithelp.ithome.com.tw/upload/images/20210923/201298739csPNtkdfW.png

这边加上了 {this.props.children} 之後,
就出现我们之前在 <Talker> 里面增加的 <p>之後将会上架更多水果,敬请期待</p> 了。

说明:
Talker.js 里面的 {this.props.children} 意思是会去找到 <Talker></Talker> 里面包的内容,
将其显示在这里,
这边架构图会是这样:
https://ithelp.ithome.com.tw/upload/images/20210923/20129873aEJ7uAIRmr.png

defaultProps

这意思是是要给予属性预设值,当该 component 没有被设定属性值的时候就要 default 显示的值。

比如说把原本按钮内的文字「点我购买!」改成 {this.props.text}

<button onClick={this.props.onClick}>{this.props.text}</button>

这时候会发现按钮的文字不见了。
https://ithelp.ithome.com.tw/upload/images/20210923/201298737alp5nW3yO.png

但我在 Button.js 下面多加了这行设定,

Button.defaultProps = { text: "销售一空" };

这样会发现即使在 Talker.js 中 <Button> 里我没给予 text 这个属性,
依然会显示「销售一空」的字眼。
https://ithelp.ithome.com.tw/upload/images/20210923/20129873uNE0DFIkLS.png

那如果我现在在 Talker.js 中 <Button> 里给予 text 这个属性并设定值,
像这样:

<Button onClick={this.handleClick} text="点我购买!" />

发现按钮文字又从「销售一空」变为「点我购买!」了。
https://ithelp.ithome.com.tw/upload/images/20210923/20129873xaa2PQl7Ry.png

这个适合在如果这个属性一定都会有预设值使用。

今日程序暨档案架构

然後我终於研究好如何在 CodeSandbox 放我在 Codecademy 的这些练习了,
因此附上今日程序:Day21 Codecademy - this.props

然後说明一下档案架构:
index.js 引入 App.js,并置入 <App />

ReactDOM.render(
  <StrictMode>
    <App />
  </StrictMode>,
  rootElement
);

因此 App.js 才是真的写主程序的地方。

App.js 引入 Fruits.js, Talker.js,
Talker.js 再引入 Button.js 。
https://ithelp.ithome.com.tw/upload/images/20210923/20129873XdZXSNbvPX.png
https://ithelp.ithome.com.tw/upload/images/20210923/20129873itKNq4Jv7Y.png

如果对 component 如何宣告及引入使用不熟悉的可以参考我昨天的文章 →
[Day20] 在 Codecademy 学 React ~ 如何宣告 Component 及使用 Component 的好处

後记

其实 this.props 也是满多东西可以学习的,
但是我之前没有写过 this.props
所以现在对我来说这样的写法有点罗嗦就是了XD
例如上面范例介绍的 {this.props.name} 之前我的写法都只会写 {name} XD

明天来学 this.state XD


<<:  【第九天 - 数字型 SQL注入】

>>:  Day08:Swift 基础语法—Loop

Day 8:先别急着撰写文章,你听过 Markdown 吗?

相信有人已经迫不及待要撰写文章了,不过在这之前,我们先来介绍一下 Markdown 这个标记语言。 ...

Progressive Web App Audits (15)

什麽是 Lighthouse Audits? Lighthouse 是一套整合在 DevTools ...

Day27:危机意识

Security Threats Denial of Service (DoS) Attack: ...

[Day25] 第二十五章-新增空白的point表单 (跨资料查询还有对应细节)

前言 昨天我们完成了point简单的read 跟route model controll等 今天我们...

ASO 的重要项目

大部分的人下载 App 都是直接在 App Store 或 Google Play 搜寻 ASO 就...