20200122のReactに関する記事は10件です。

TypeScriptでstyle-componentsの"as" propにNextLinkコンポーネントを渡したい時

実装したかったこと

labelコンポーネントにおいて、リンク付きにしたい箇所とリンクなしにしたい箇所があったので、<a>に置き換えるものと置き換えないで<label>のままにしておくものを作りたい。

やったこと

as propを使用し解決しようとしました。

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <CategoryLabel as={Link} href={href}>
        {title}
    </CategoryLabel>
);

これでいけると思いました。怒られました

Types of property 'as' are incompatible.
    Type 'typeof Link' is not assignable to type 'string | UrlObject | undefined'.
          Type 'typeof Link' has no properties in common with type 'UrlObject'.

これは、参照できるasではないよ。

Urlobjectが未定義だよ。

types of LinkにはUrlObjectと共通のプロパティがないよ。と言われました。

とりあえずエラーをもとに、styled-componet ts as linkのワードでググりました。

すると同じようなことで悩んでるZeit公式のissueにぶつかりました。

image.png

こうしたらいけると公式が言うからいけるのでしょう!

やってみます。

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <Link href={href} passHref>
        <CategoryLabel as="a">
            {title}
        </CategoryLabel>
    </Link>
);

できました!!!!!!!!

image.png

(レイアウトは今作り段階なのでゴミです許してください)

何がダメだったのか?

こちらはNext.jsの公式 Routingのところから抜粋したものです。

image.png
Next.jsのRoutingで設定してるasとstyled-componentで設定しようとしたasが被っていた。
Next.jsのRoutingのasをTypeScript側は、参照しようとしるのに、私がstyled-componentのasを提示したため、types of LinkにはUrlObjectと共通のプロパティがないよと言うエラーになったと言うわけです。

ちなみに

現時点でわかったasが受け取れるものは以下です。

  • HTMLのネイティブタグを文字列で渡す
  • styled-componentで作ったコンポーネントタグを{component}で渡す

なので下のコードも通ります。

export default CategoryLabel;

const Foo = styled.h1`
`;

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <CategoryLabel as={Foo}>
        {title}
    </CategoryLabel>
);

以上です!
メンヘラなので、何か助言あれば優しい言葉でお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TypeScriptでstyled-componentsの"as" propにNextLinkコンポーネントを渡したい時

実装したかったこと

<label>要素において、リンク付きにしたい箇所とリンクなしにしたい箇所があったため、以下のように2通りのケースに対応できるようにしたい。

  • <label>をベースにスタイルを定義する。
  • <label><a>に置き換えて、スタイルは全く同じものを使用する。

やったこと

"as" prop を使用し解決しようとしました。

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <CategoryLabel as={Link} href={href}>
        {title}
    </CategoryLabel>
);

これでいけると思いました。怒られました

Types of property 'as' are incompatible.
    Type 'typeof Link' is not assignable to type 'string | UrlObject | undefined'.
          Type 'typeof Link' has no properties in common with type 'UrlObject'.

これは、

  • "as" の型が間違ってるよ。
  • Link の型は ("as" で要求されている) string | UrlObject | undefined のどれにも該当しないよ。
  • Link の型は (唯一オブジェクトとして検査する価値のある) UrlObject のプロパティと構成が全く違うよ。

と言われました。とりあえずエラーをもとに、styled-componet ts as linkのワードでググりました。すると同じようなことで悩んでるZeit公式のissueにぶつかりました。

image.png

こうしたらいけると公式が言うからいけるのでしょう!やってみます。

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <Link href={href} passHref>
        <CategoryLabel as="a">
            {title}
        </CategoryLabel>
    </Link>
);

できました!!!!!!!!

image.png

(レイアウトは今作り段階なのでゴミです許してください)

何がダメだったのか?

こちらはNext.jsの公式 Routingのところから抜粋したものです。

image.png

  1. Next.jsのRoutingで設定してるasとstyled-componentで設定しようとしたasが被っていた。
  2. Next.jsのRoutingのasをTypeScript側は参照しようとしているのに、私がstyled-componentのasを提示した。

このため

Link の型は (唯一オブジェクトとして検査する価値のある) UrlObject のプロパティと構成が全く違うよ。

と言うエラーになったと言うわけです。

ちなみに

現時点でわかったasが受け取れるものは以下です。

  • HTMLのネイティブ要素名(文字列)
  • styled-componentで作ったコンポーネント(オブジェクト)

なので下のコードも通ります。

export default CategoryLabel;

const Foo = styled.h1`
`;

export const CategoryLink: React.FunctionComponent<LinkProps> = ({
    title = 'メンヘラ',
    href,
}) => (
    <CategoryLabel as={Foo}>
        {title}
    </CategoryLabel>
);

以上です!
メンヘラなので、何か助言あれば優しい言葉でお願いします。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React.Componentのメンバ変数は、再レンダー時に更新されるとは限らない!

ReactでsetState()しても値が更新されなくてハマったので、記事化します。

更新すべき値をメンバ変数に格納した場合

ボタンを押すと値が+1されるアプリケーションを作ります。

以下は間違ったコードです。
Appでカウンターの値を管理し、Counterはその値とカウントボタンを表示します。

app.js
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from './counter'

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {count: 0}
    this.increment = this.increment.bind(this)
  }

  increment() {
    this.setState(
      (state) => {return {count: state.count + 1}}
    )
  }

  render() {
    return (
      <Counter count={this.state.count} onClick={this.increment} />
    )
  }
}

let app = document.getElementById('app')
ReactDOM.render(<App />, app)

counter.js
import React from 'react'

class Counter extends React.Component {
  constructor(props) {
    super(props)
    this.count = this.props.count
  }

  render() {
    // 以下の`this.count`は、新しいpropsを反映しない!
    return (
      <div>
        <p>{this.count}</p>
        <button onClick={this.props.onClick}>カウント</button>
      </div>
    )
  }
}

export default Counter

このコードを実行し、ボタンをクリックしても、カウンターの値は増加しないと思います。

レンダーごとに更新する値は、メンバ変数に保存しない

値が更新されない原因は、表示する値がthis.countになっていることです。
counter.jsを以下のように修正すれば、ちゃんとカウント値が増加します。

counter.js
import React from 'react'

class Counter extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <div>
        <p>{this.props.count}</p>
        <button onClick={this.props.onClick}>カウント</button>
      </div>
    )
  }
}

export default Counter

今回は、this.props.countを表示するだけなので、わざわざメンバ変数に格納することはありませんが、表示させるべき値が複雑になる場合、renderメソッドの戻り値に直接式を書かずに、結果を変数に格納したい場合があります。そういう場合は、たとえば関数にすると良いと思います。

counter.js
class Counter extends React.Component {
  constructor(props) {
    super(props)
  }

  render() {
    let count = this._getCount()
    return (
      <div>
        <p>{count}</p>
        <button onClick={this.props.onClick}>カウント</button>
      </div>
    )
  }

  _getCount() {
    let count;
    // すごく複雑な処理
    return count
  }
}

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React勉強の備忘録

React HooksのuseState

React HooksのuseStateがどういう原理で実現されてるのかさっぱりわからなかったので調べた
https://sbfl.net/blog/2019/02/09/react-hooks-usestate/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

base64形式にして画像を表示できるようにする React

初めてbase64を使ったのでメモ

base64とは

この記事を読むとわかる
base64ってなんぞ??理解のために実装してみた

base64に変換してくれるサイト

画像をbase64に変換してくれるサイト

実際にbase64化されたURLをブラウザで検索して、画像が表示されてたらbase64化できてる

実装方法

logo.js
export const logo ="base64形式のURL"
App.js
import logo from './logo'

(コード省略)
<img src={logo} alt={画像が表示されない時に代わりに表示したい文字} />

画像を export して 読み込みたいところでimportして使える!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[React]どこからか受け取ったHTMLの文字列を、HTML要素として画面に表示しつつ、特定ワードでハイライトしたい

背景

開発中のシステムで、データベースにHTMLが入っているカラムがあり、それをAPIで取ってきて、Reactで表示するという構成の画面があります。
その画面にはHTML内の文字列を検索できる機能があり、「検索ワードをハイライトして表示できないか?」という相談を受けたので、実装しました。

(Google検索だと、ハイライトではなく太字になっていますが、やりたいことはこんな感じです)
Screen Shot 2020-01-22 at 4.59.49.png

ただ文字列をハイライトするのはかんたんですが、HTMLとしてレンダリングしつつというところで少し悩んだので記事にしました。

できたもの

だいたいこのような感じです。

Jan-22-2020 05-30-59.gif

HTMLに対して、スペース区切りで文字を入力したら、入力された文字とマッチする箇所をハイライトします。

codesandboxに上げました。

Edit react-innerHTML-highlight-words

ポイント

文字をハイライトさせるのには、react-highlight-wordsというパッケージが便利だったので使っています。
処理の流れは、

  1. (HTMLのstring)HTMLをstateから受け取る
  2. (React elementでstringをラップ)ハイライトしてくれるコンポーネントに突っ込む
  3. (HTMLのstring)react-dom/serverでサーバで一旦レンダリングする
  4. (HTMLのstring)正規表現でHTMLタグをアンエスケープする
  5. (React Element)dangerouslySetInnerHTMLというHTMLのstringをReactでHTML要素として表示できるプロパティに入れる

という感じです。
もしかしたらもっといいやり方があるかもですね。

HTMLタグのアンエスケープはこれでできます。

    const unescapeHtml = string => {
      const patterns = {
        "&lt;": "<",
        "&gt;": ">",
        "&amp;": "&",
        "&quot;": '"',
        "&#x27;": "'",
        "&#x60;": "`"
      };

      const escapedString = string.replace(
        /&(lt|gt|amp|quot|#x27|#x60);/g,
        match => patterns[match]
      );

      return escapedString;
    };

注意

HTML内部のリンクとマッチするワードが入力されたら、HTMLがこわれます。
必要ならエスケープすることになります。
また、もととなるデータが、ユーザーが自由に入れることができるものである場合は、XSS対策などセキュリティ対策が必要です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactで行数可変なtextareaを作った話

TL;DR

タイトルなし.gif

中身に応じて高さが変わるtextareaが出来た
コピペ、複数行まとめて削除しても大丈夫

軽く検索しても出てこなかったので
似たようなことをしたくなった人や未来の自分のために書いてみました

環境

react:15.6.2
redux-form:6.8.0
lodash.isempty:4.4.0

正直reactだけでもOKなはず
廃止されるライフサイクルメソッドなども使っていないので最新版のreactでも動くと思います

他2つは細かいところ書くのが面倒なので使ってます
無くても本質には関係ないので大丈夫です

chromeとIEで動作確認済み(バージョンはわからないですが2020/01付近です)

参考

textareaの大きさを自動調整

実装

細かいところはフィーリングで読んでください

index.js
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import TextArea from './textArea';

function index() {
  return (
    <div>
      <Field name="TextArea" component={TextArea} rows={2} />
    </div>
  )
}

export default reduxForm({ form: 'form' })(index);
textArea.js
import React, { Component } from 'react';
import isEmpty from 'lodash.isempty';

class TextArea extends Component {
  constructor(props) {
    super(props);
    this.textArea = null;
  }

  shouldComponentUpdate(nextProps) {
    if (this.props.input.value !== nextProps.input.value) {
      if (isEmpty(nextProps.input.value)) {
        this.textArea.setAttribute('rows', this.props.rows);
      } else {
        this.textArea.setAttribute('rows', this.props.rows);
        while (this.textArea.scrollHeight > this.textArea.offsetHeight) {
          const tempRows = Number(this.textArea.getAttribute('rows'));
          this.textArea.setAttribute('rows', tempRows + 1);
        }
      }
    }
    return true;
  }

  render() {
    return (
      <textarea
        ref={c => {
          this.textArea = c;
        }}
        style={{ resize: 'none' }}
        name={this.props.input.name}
        onChange={e => this.props.input.onChange(e.target.value, this.props.input.name)}
        rows={this.props.rows}
      />
    );
  }
}

解説

参考にしたコードと似たようなことをしています
以下の部分が全てです

  shouldComponentUpdate(nextProps) {
    // textareaの内容が変更された時のみ操作
    if (this.props.input.value !== nextProps.input.value) {
      if (isEmpty(nextProps.input.value)) {
        // 内容が空なら初期値の行数に戻すだけ
        this.textArea.setAttribute('rows', this.props.rows);
      } else {
        this.textArea.setAttribute('rows', this.props.rows);
        // 内容が有るならスクロールせずに表示できる高さになるまで初期値から1行ずつ増やす
        while (this.textArea.scrollHeight > this.textArea.offsetHeight) {
          const tempRows = Number(this.textArea.getAttribute('rows'));
          this.textArea.setAttribute('rows', tempRows + 1);
        }
      }
    }
    return true;
  }

注意点

高さにmax-heightなどで上限を定めたい時は
直接textareaにmax-heightを書かないでください

高さの計算とぶつかるのか無限ループになってブラウザが固まります
高さを決めたい場合は適当にラップしてそちらに色々設定してください

※今回で言うと、index.jsのdivに{max-height: 100px, overflow-y: scroll}みたいにすれば
100pxより入力欄が高くなったらスクロールになるよう切り替えられます

まとめ

shouldComponentUpdateでこういうことして良いのかはわかりませんがとりあえず動いてるのでヨシとします
横方向(cols)にも同じ方法で拡縮できるのではないかと思いますがそこまでは試してないです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】Next.jsをfirebaseにデプロイする方法

package.jsonを修正

"start"に「-p $PORT"」を追記かつ、"export"を追加

  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start -p $PORT",
    "export": "next export"
  },

build & export

以下コマンドを叩いて、ビルドする

npm run build

そのあと、エクスポートする

npm run export

build&exportに成功するとoutフォルダに、静的ファイルが吐き出される

firebaseのデプロイ準備

まずは、以下コマンドを叩く

firebase init

各質問に答えていき、以下の質問の際に「out」を入力する

? What do you want to use as your public directory? out

firebase.jsonに正しい内容が記載されていることを確認して、デプロイ実行

firebase deploy

以上!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デザイナがReactを始める前に押さえておきたいJavascriptの基本③(クラス編)

はじめに

テーブルレイアウトからcssスタイリングへの過渡期だった頃:sweat_smile:、私はWebデザイナーを目指し始めました。
それから◯年あまりの間、ビジュアルを作ったり、HTML・CSS・jQuery(コピペ多め)でのマークアップをやってまいりました。

そんな中、ここ最近急速にフロントエンド界隈の難易度が上がり、今までデザイナが担当していた分野のフロントエンドコーディングにおいても、より専門性の高いJSコーディングスキル、Reactなどの知識が求められるようになりました。

自身がReactを学ぶ上で色々とつまずき、心折れそうになった理由は、Javascriptの配列・オブジェクト・クラスをきちんと理解しないまま始めてしまったから。
この経験に基づき、デザイナがReactを始める前に最低限押さえておくべきJavascriptの基本(個人的見解)について、3回(予定)に分けて書きます。

クラス構文

オブジェクトをテンプレート化できるのがクラス構文です。
色々な関数をひとまとめにして使い回せたり、他のクラスに内容を引き継ぐことができるので、よりメンテナンス性の高いコードを書くことができます。

(前提知識としてオブジェクトの基本への理解が必要です。)

クラス構文に書き換えてテンプレートを作る

まずはJavascriptの基本②(オブジェクト編)の復習も兼ねて、複数オブジェクトの配列とメソッドを使って多角形の内角の和を求めるコードを作成し、そこからクラス構文を使ったテンプレートを作っていきます。

図形 含まれる三角形の数 内角の和
3角形 1 180°
4角形 2 360°
5角形 3 540°
6角形 4 720°
const insideAngleSums = [
  {
    n: 3, //3角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 4, //4角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 5, //5角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 6, //6角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  }
]
insideAngleSums[0].getAngleSum() //3角形の内角の和は180°
insideAngleSums[1].getAngleSum() //4角形の内角の和は360°
insideAngleSums[2].getAngleSum() //5角形の内角の和は540°
insideAngleSums[3].getAngleSum() //6角形の内角の和は720°
図形 含まれる三角形の数 内角の和
n角形 n-2 180°* (n-2)

n角形の内角の和の公式は
180 * (n - 2)

クラス構文を使って、この公式をテンプレート化してみます。
コンストラクタはインスタンス生成時に呼び出される関数です。

class InsideAngleSum { //classの最初の I は大文字
  constructor(n){ //constructor()で初期化し、nの値には引数を渡してセット
    this.n = n //このクラスから作られるインスタンスはthisで表現できる
  }
  getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
}
const insideAngleSums = [
  //newを使ってインスタンスを作る
  new InsideAngleSum(3),
  new InsideAngleSum(4),
  new InsideAngleSum(5),
  new InsideAngleSum(6)
]

insideAngleSums.forEach(insideAngleSum => insideAngleSum.getAngleSum())
//3角形の内角の和は180°
//4角形の内角の和は360°
//5角形の内角の和は540°
//6角形の内角の和は720°

テンプレートする前と同じ結果になりました。
ちなみに100角形の内積の和を求めてみると。。

new InsideAngleSum(100).getAngleSum() // 100角形の内角の和は17640°

クラスの継承

さらにclass構文は、内容を他のclass構文に引き継げるので、もともと書かれている構文を変更せずに内容の追加などを行なうことができます。

まず三角形の面積を求める公式をクラスにしてみます。
底辺 * 高さ / 2 から、

class Triangle {
  constructor(width, height){
    this.width = width
    this.height = height
  }
  area(){console.log(`底辺${this.width}cm 高さ${this.height}cm の三角形の面積は、${this.width * this.height / 2}㎠ です。`)}
}

n角形の内角の和の公式を親クラス、三角形の面積の公式を子クラスとして継承させてみます。
(クラスの仕組みを説明するという目的達成のために、無理やりなコードになってしまってるかも:innocent:

class InsideAngleSum { //親クラス
  constructor(n){
    this.n = n
  }
  getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  //staticで始まる静的メソッドはインスタンスを介さずに、直接クラスから呼び出せる。(インスタンスを介さないので、thisは使えない)
  static outsideAngleSum(){console.log('多角形は何角形でも外角の和は360°')} 
}

class Triangle extends InsideAngleSum { 
//extends InsideAngleSumでInsideAngleSumクラスに書かれたコードが、そのまま Triangle クラスに引き継がれる
  constructor(n, width, height){
  //子クラスの constructor()で this を使うには constructor()の最初に super()と記述。親クラスの constructor()が呼ばれ、親クラスで引数も渡しているのでここでも渡す。
    super(n)
    this.width = width
    this.height = height
  }
  polygon(){console.log(`${this.n}角形!!`)}
  area(){
    console.log(`底辺${this.width}cm 高さ${this.height}cm の三角形の面積は、${this.width * this.height / 2}㎠ です。`)
    super.getAngleSum() //親クラスのメソッドを呼ぶには、super をつける。
    this.polygon() // 子クラスのthisは定義されたクラス自身のメソッドを指す
    InsideAngleSum.outsideAngleSum() //静的メソッドはクラスから直接呼び出せる。
  }
}

const info = new Triangle(12, 5, 8)
console.log(info.area())
//底辺5cm 高さ8cm の三角形の面積は、20㎠ です。
//12角形の内角の和は1800°
//12角形!!
//多角形は何角形でも外角の和は360°

シンプルにまとめられました :thumbsup_tone1::thumbsup_tone1:

最後に

道半ばですが、分からないことがあっても諦めずに少しずつすすめると、小さな成長を感じる瞬間があります。
そんな素敵な瞬間を楽しみながら頑張ろうと思っております:innocent:
フロントエンドスキルを武器にしたいWebデザイナーのみなさん、一緒にがんばりましょう!

次回からはReact入門編の記事をシリーズで書いてみたいと思います。

参考にさせていただいたサイト

https://developer.mozilla.org/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

デザイナがReactを始める前に押さえておきたいJavaScriptの基本③(クラス編)

はじめに

テーブルレイアウトからcssスタイリングへの過渡期だった頃:sweat_smile:、私はWebデザイナーを目指し始めました。
それから◯年あまりの間、ビジュアルを作ったり、HTML・CSS・jQuery(コピペ多め)でのマークアップをやってまいりました。

そんな中、ここ最近急速にフロントエンド界隈の難易度が上がり、今までデザイナが担当していた分野のフロントエンドコーディングにおいても、より専門性の高いJSコーディングスキル、Reactなどの知識が求められるようになりました。

自身がReactを学ぶ上で色々とつまずき、心折れそうになった理由は、JavaScriptの配列・オブジェクト・クラスをきちんと理解しないまま始めてしまったから。
この経験に基づき、デザイナがReactを始める前に最低限押さえておくべきJavaScriptの基本(個人的見解)について、3回(予定)に分けて書きます。

クラス構文

オブジェクトをテンプレート化できるのがクラス構文です。
色々な関数をひとまとめにして使い回せたり、他のクラスに内容を引き継ぐことができるので、よりメンテナンス性の高いコードを書くことができます。

(前提知識としてオブジェクトの基本への理解が必要です。)

クラス構文に書き換えてテンプレートを作る

まずはJavaScriptの基本②(オブジェクト編)の復習も兼ねて、複数オブジェクトの配列とメソッドを使って多角形の内角の和を求めるコードを作成し、そこからクラス構文を使ったテンプレートを作っていきます。

図形 含まれる三角形の数 内角の和
3角形 1 180°
4角形 2 360°
5角形 3 540°
6角形 4 720°
const insideAngleSums = [
  {
    n: 3, //3角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 4, //4角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 5, //5角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  },
  {
    n: 6, //6角形
    getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  }
]
insideAngleSums[0].getAngleSum() //3角形の内角の和は180°
insideAngleSums[1].getAngleSum() //4角形の内角の和は360°
insideAngleSums[2].getAngleSum() //5角形の内角の和は540°
insideAngleSums[3].getAngleSum() //6角形の内角の和は720°
図形 含まれる三角形の数 内角の和
n角形 n-2 180°* (n-2)

n角形の内角の和の公式は
180 * (n - 2)

クラス構文を使って、この公式をテンプレート化してみます。
コンストラクタはインスタンス生成時に呼び出される関数です。

class InsideAngleSum { //classの最初の I は大文字
  constructor(n){ //constructor()で初期化し、nの値には引数を渡してセット
    this.n = n //このクラスから作られるインスタンスはthisで表現できる
  }
  getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
}
const insideAngleSums = [
  //newを使ってインスタンスを作る
  new InsideAngleSum(3),
  new InsideAngleSum(4),
  new InsideAngleSum(5),
  new InsideAngleSum(6)
]

insideAngleSums.forEach(insideAngleSum => insideAngleSum.getAngleSum())
//3角形の内角の和は180°
//4角形の内角の和は360°
//5角形の内角の和は540°
//6角形の内角の和は720°

テンプレートする前と同じ結果になりました。
ちなみに100角形の内積の和を求めてみると。。

new InsideAngleSum(100).getAngleSum() // 100角形の内角の和は17640°

クラスの継承

さらにclass構文は、内容を他のclass構文に引き継げるので、もともと書かれている構文を変更せずに内容の追加などを行なうことができます。

まず三角形の面積を求める公式をクラスにしてみます。
底辺 * 高さ / 2 から、

class Triangle {
  constructor(width, height){
    this.width = width
    this.height = height
  }
  area(){console.log(`底辺${this.width}cm 高さ${this.height}cm の三角形の面積は、${this.width * this.height / 2}㎠ です。`)}
}

n角形の内角の和の公式を親クラス、三角形の面積の公式を子クラスとして継承させてみます。
(クラスの仕組みを説明するという目的達成のために、無理やりなコードになってしまってるかも:innocent:

class InsideAngleSum { //親クラス
  constructor(n){
    this.n = n
  }
  getAngleSum(){console.log(`${this.n}角形の内角の和は${180 * (this.n - 2)}°`)}
  //staticで始まる静的メソッドはインスタンスを介さずに、直接クラスから呼び出せる。(インスタンスを介さないので、thisは使えない)
  static outsideAngleSum(){console.log('多角形は何角形でも外角の和は360°')} 
}

class Triangle extends InsideAngleSum { 
//extends InsideAngleSumでInsideAngleSumクラスに書かれたコードが、そのまま Triangle クラスに引き継がれる
  constructor(n, width, height){
  //子クラスの constructor()で this を使うには constructor()の最初に super()と記述。親クラスの constructor()が呼ばれ、親クラスで引数も渡しているのでここでも渡す。
    super(n)
    this.width = width
    this.height = height
  }
  polygon(){console.log(`${this.n}角形!!`)}
  area(){
    console.log(`底辺${this.width}cm 高さ${this.height}cm の三角形の面積は、${this.width * this.height / 2}㎠ です。`)
    super.getAngleSum() //親クラスのメソッドを呼ぶには、super をつける。
    this.polygon() // 子クラスのthisは定義されたクラス自身のメソッドを指す
    InsideAngleSum.outsideAngleSum() //静的メソッドはクラスから直接呼び出せる。
  }
}

const info = new Triangle(12, 5, 8)
console.log(info.area())
//底辺5cm 高さ8cm の三角形の面積は、20㎠ です。
//12角形の内角の和は1800°
//12角形!!
//多角形は何角形でも外角の和は360°

シンプルにまとめられました :thumbsup_tone1::thumbsup_tone1:

最後に

道半ばですが、分からないことがあっても諦めずに少しずつすすめると、小さな成長を感じる瞬間があります。
そんな素敵な瞬間を楽しみながら頑張ろうと思っております:innocent:
フロントエンドスキルを武器にしたいWebデザイナーのみなさん、一緒にがんばりましょう!

次回からはReact入門編の記事をシリーズで書いてみたいと思います。

参考にさせていただいたサイト

https://developer.mozilla.org/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む