20200914のJavaScriptに関する記事は30件です。

【JavaScript, jQuery】nullとremoveメソッドを使ったif文で、click表示を1つだけに収める方法(+α oneメソッドとの比較)

「ボタンを連打したら何個も同じメッセージが生成されてうざったい。1つだけの生成でいいのに。」
・・・この問題を解決するコード記述で詰まったので、備忘として残す。

例えば下記のような挨拶ボタンを作りたいとする。
html.png
プレビューはこんな感じ(cssの記述は、内容と直接関係ないので割愛。)
※黒い部分はただの墨塗りです。気にしないでください。
shoki.png

挨拶ボタンを押すと、「こんにちは!私の名前は(以下略)」と定型文を出力するようにする。
oomoto.png

しかし、このままだと挨拶ボタンをクリックする度にメッセージが何個も出てくる。
dame.png

click表示(挨拶メッセージ)1つだけに収めたいので、下記のようにnullを使ったif文を関数の中に追記する。
kairyou.png
つまり、if文で「あるHTML要素がすでに存在している場合(nullではない場合)」と「存在している場合(else)」の処理をそれぞれ実行できるようにする。
「!= null」は、null(不存在)ではないという意味。
その結果、何度ボタンを押してもclick表示は1つだけしか表示されない。
(正確には、「(ボタンを2回目以降押した場合は、一度既存の表示を削除(remove)し、あらたに生成(append,text)」している。)
okay.png

「挨拶ボタンのclickイベントを1回だけしか実行させない。」という目的だけを実現するのであれば、oneメソッドを使った方が簡素な記述で済む。
例)

$("#btn-greeting").one("click",function() {
 $("#greeting").text(greeting());
});

今回のように、決まった定型文を出力する場合はこれでもよい。
しかし、「10歳の田中太郎」以外も挨拶ボタンを使いたい場合、つまり挨拶文の内容(名前や年齢)を変更し、ボタンを押すことで更新(再表示)するようなプログラムを作成したい場合は、oneメソッドでは融通が利かないため、前述のif文が有効である。

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

vue.jsでA-Framを使う

vue.jsでA-Framを使用した時に出た警告

Consoleに警告が出てけすのに消すのに手こずるたのでメモ

A-Frameは、のなどの専用タグを使用します。
vueファイル内に書くと以下のような警告が出ます。

[Vue warn]: Unknown custom element: 
<a-entity> - did you register the component correctly?
 For recursive components, make sure to provide the "name" option.

scriptの中に以下を追加する。(使用するa-〇〇をすべて追加)

<script>
        Vue.config.ignoredElements = [
      'a-scene',
      'a-entity',
      'a-camera',
      'a-box',
      'a-ring',
      'a-asset-items',
      'a-assets',
      'a-cursor',
      'a-text',
      'a-light',
    ]
</script>

以上。

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

[Javascript] 指定した範囲の整数を取得するランダムクラスの作成

概要

指定した範囲の整数、指定した文字列をランダムで取得する方法について class を利用して記述する。本記事では class の書き方、Math.floor(), Math.random() についてまとめる

前提知識

Javascript の基礎知識

ランダムクラスの作成

.js
//ランダムクラスの作成
class Random {
    intRange(min,max){
      // min ~ max の間のランダムな整数を取得(詳細は「乱数の取得(数値)方法」に記載)
    // min (include), max(exclude)
      return Math.floor(min + (max-min) * Math.random()) 
    }
}

const getRandomInt = () => {
   //ランダムクラスのインスタンス化
    const Random = new Random();
    for (let i = 0; i <20;i++){
    //ランダムクラスのintRangeの実行
      const ans = Random.intRange(18,66);
      console.log(ans);
  }
}

getRandomInt();

クラスとは?

複数の関数をパッケージ化することができる。プログラミングでは機能ごとにクラスにまとめることが主らしい。
クラスの宣言 → インスタンス化 → クラスの関数を実行 という3つのステップが必要。
ここでは「ランダムクラス」を作成して、ランダムクラスの中にあるランダムな整数を取得する機能を実行する(以下はイメージ図)

スクリーンショット 2020-09-14 22.15.01.png

クラスを呼ぶと同時に行う処理を「コンストラクタ」という。ここでは割愛する。

.js
//クラスの構文
class クラス名 {
    関数名(){
        関数の中身
    }
}

//インスタンス化の構文
const クラスのインスタンス = new クラス名();

//実行時の構文
クラス.関数名

クラスの中で関数を宣言するときは const/let は不要

乱数の取得(数値)方法

Math.random() // 0 以上 1 未満の浮動小数点の取得

Math.random() は 0 以上 1 未満の値をランダムで返す

.js
const randomFloat = Math.random();
console.log(randomFloat)

Math.floor() // 切り捨て

整数を返したい場合は切り捨ての Math.floor()を利用する

.js
const randomInt = Math.floor(Math.random());
console.log(randomInt)

最大値と最小値を指定し、その範囲の整数を取得

最大値(max) と最小値(min) を指定したい場合は以下のように記述する

.js
const randomInt = Math.floor (min + (max -min) * Math.random());
console.log(randomInt)

Math.random() は 0 以上 1 未満の値をランダムで返すため、min(include), max(exclude) であることに注意
ex.) 0 ~ 10 の値を取得したい場合は min = 0, max = 11

※計算式((min + (max -min) * Math.random())は線形補間の計算式
参考:2点間の線形補間を計算する
スクリーンショット 2020-09-12 20.23.57.png

配列の要素(文字列)を取得

Math.randomMath.floor を利用すると、配列の要素(文字列)を取得することができる

ex.) クラスを利用して記載

class.js
//クラスの作成
class Random {
  //関数の定義
    intRange(min,max){
      return Math.floor(min + (max-min) * Math.random()) 
    }
}

クラスを記載するファイルと、実行ファイルを分けて管理するのが一般的らしい

.js
//リスト作成
const prefList = ["東京都","大阪府","福岡県"]

//prefList からランダムで一つ取得
const getRandomPref = (list) =>{
 //インスタンス化
  const random = new Random();
 //Random クラスの関数を呼び出し
  const prefListNum = random.intRange(0,list.length);
  return list[prefListNum];

ex.) 関数を利用して記載

.js
//リスト作成
const prefList = ["東京都","大阪府","福岡県"]

//リストの任意の要素を取得する関数を作成
const getRandomPref = (list) =>{
 //取得する要素の番号を求める。list.length にはここでは「3」 
  const prefListNum = Math.floor(Math.random() * list.length);
  console.log(list[prefListNum]);
}

getRandomPref(prefList);

他の人に共有する場合、クラスを利用していると、クラスの重複がなければクラスで定義した関数を実行することができる。(関数のまま共有すると、関数名が重複していたりすると混乱する)

まとめ

  • クラスを利用すると、複数の関数をパッケージ化できる
  • 使い方は3ステップ:クラスの定義→インスタンス化→呼び出し
  • 乱数を取得したいとき:Math.random
  • 切り捨てたいとき: Math.floor()
  • 指定した任意の文字列を取得したいとき:配列を作成し、取得する要素の番号を Math.floor(Math.random()* 配列の長さ) で求める

参考ページ

[JavaScript入門]乱数の作り方(範囲指定/重複なし/ランダム文字列)
JavaScriptのクラスを学ぶ演習・課題

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

TypeScriptとJavaScriptの違いとTypeScriptの特徴

プログラミング勉強日記

2020年9月14日
JSのフレームワークやライブラリについてまとめてきたが、今回はJSを拡張して作られたTypeScriptについてまとめる。

TypeScriptとは

 2014年にMicrosoftによって開発されたJavaScriptを拡張して作られたプログラミング言語。TypeScriptで書いたコードをコンパイルするとJSのコードに変換されているので、JSファイルが実行できる環境であればすぐに使うことができ、JSライブラリもTypeScriptから使用できる。
 TypeScriptはチーム開発に向いていて、エラーを防ぎやすいように設計されている。

JavaScriptとの違い

  • JavaScriptは動的型付け、TypeScriptは静的型付け
  • TypeScriptはクラスの作成が可能
  • TypeScriptはJavaScriptと同様の構文を使うことができる

JavaScriptは動的型付け、TypeScriptは静的型付け

 変数のデータ型に関するもの。JSでは実行時にデータ型が自動で決まる動的型付けであり、コードを気軽に書けるが、実行しないとエラーがわからない。PythonやRubyも動的型付けである。
 TypeScriptは変数のデータ型をあらかじめ決めることのできる静的型付けであり、コンパイルする時点でエラーがわかるだけでなく、コードが読みやすい。

TypeScriptはJavaScriptと同様の構文を使うことができる

 TypeScriptはJSの機能を拡張して作られているので、JSの構文を使うことができる。

特徴

  • JavaScriptより短く読みやすいコードを書ける
  • JavaScriptとの互換性がある
  • 型を宣言するためのエラーを未然に防ぐことができる
  • 学習コストがかかる
  • 日本語の情報が少ない

JavaScriptより短く読みやすいコードを書ける

 TypeScriptではクラスが作成できるので、JSよりも短く読みやすいコードをかける。また、同様の機能を実装する場合は、TypeScriptの方がコードは簡潔で、TypeScriptエディタのコード補完機能を使えばよりスムーズに書ける。

JavaScriptとの互換性がある

 TypeScriptとJSは互換性があるので、JSの開発環境があれば簡単に導入することができ、JSファイルをTypeScriptから呼び出して使うこともできる。

型を宣言するためのエラーを未然に防ぐことができる

 変数の型をコード内で宣言できるので、エラーを未然に防ぐことができ、動作も早い。

学習コストがかかる

 クラスの作り方やデータ型の設定方法といった知識が必要である。ただ、JSができれば難しくは内。

日本語の情報が少ない

 TypeScriptは比較的新しい言語なので、日本語で書かれた情報が少ない。

参考文献

TypeScriptを入門者向けに解説!JavaScriptとの違いや勉強法までわかりやすく
TypeScriptとは? Webアプリ開発で注目の言語を初心者向けに徹底解説

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

とても簡単なReactの良さが5分以内に分かる例

はじめに

Web開発のフロントエンドがjQueryからReactへ移った技術改革は、「仮想DOM」「DOM操作をしない」「コンポーネント志向」という文脈で持て囃されて語れます。
しかしこれらの何が嬉しいのか?という方も居ると思います。従来の私もそうでした。

今ではこれらの有難みが分かりますが、実際にフロントエンドコーディング自体が想像しづらいと気付きづらいかなとも思います。
そこで今回はReactの感動に気づいてもらうことを目的に、簡素な例を用意しました。

対象読者は、jQueryは使えるがReactは聞いたことがあり、JSXの書き方くらいは知ってるけどメリットがイマイチ...と思っている方です。

注意

・Reactに関わらずAngularやVue等も含めても成り立つのでしょうが、その2つはほとんど書けないので触れておかないことにします。

・細かい部分は端折り雰囲気重視です。

カウンターアプリ

まずは初期値は0で、ボタンを押すと値が増えていくアプリを作りたいと思います。
マークアップから用意していきます。

<!DOCTYPE html>
<html>
  <head>
    <title>Title</title>
    <!-- Required meta tags -->
    <meta charset="utf-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
  </head>
  <body>
    <p id="value"></p>
    <p><button id="increment">Increment</button></p>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="js/index.js"></script>
  </body>
</html>

※小ネタ:VsCodeを使う際にjQueryを含んだ簡単なマークアップテンプレートを用意するには、Bootstrap 4, Font awesome 4, Font Awesome 5 Free & Pro snippets という拡張機能をインストールし、b4-$で入力補完すると手軽に生成できます。

値の表示要素は#value、ボタンは#incrementと決めました。
これを素にJSの処理を書いていきます。

// 初期値は0。それをvalueに表示させる
var value = 0;
$('#value').html(value);

// ボタンをクリックしたら...
$('#increment').on('click', function () {
  value = value + 1; // valueを1増加させて
  $('#value').html(value); // それを表示させる
});

ここでコードを眺めてみましょう。データの操作とDOMへのデータ反映に分かれていますね。
そこで、データ反映を行う部分をそれっぽい関数名にしてみましょう。

var value = 0;
render();

$('#increment').on('click', function () {
  value = value + 1;
  render();
});

function render() {
  $('#value').html(value);
}

こんな感じになりました。今の例では恩恵があるか微妙ですが、valueに相当するものが増えた場合にこれは威力を発揮するでしょう。
ところが、何となくrender()が2箇所に現れていてスッキリしないと思いませんか?
valueの更新を行ったら、自動でDOMにも反映されていて欲しいですね...。

願わくば、

var value = 0;
render();

$('#increment').on('click', function () {
  value = value + 1;
});

function render() {
  $('#value').html(value);
}

こんなものが理想ですが、実際に動きません。

それを実現してくれるのがReactです!

先程を同じカウンターをReactで作ってみましょう。
create-react-appと使ってプロジェクトを作ります。
ついでに、ES7 React/Redux/GraphQL/React-Native snippetsという拡張機能もインストールしておきましょう。

npx create-react-app counter-react
...(省略)...
cd counter-react
npm run start

デフォルトのマークアップが入っています。邪魔なので消しましょう。
index.cssApp.cssの中身を空にします。

create-react-appで生成したReactプロジェクトの初歩は、
以下のreturnされるdiv要素内にマークアップやロジック等の処理を書くことになります。

import React from 'react';
import './App.css';

function App() {
  return (
    <div>
      {/* ここに書く */}
    </div>
  );
}

export default App;

ではReact版のカウンターを早速作りましょう。
ReactはコンポーネントというものでUIを管理します。コンポーネント名はCounterを付けておきます。

import React from 'react';
import './App.css';

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

このままでは<Counter />が存在しないのでコンパイラに怒られます。
そこで<Counter />を定義していきます。

Reactにはpropsstateというパラメータがあります。前者は関数の引数、後者は関数のローカル変数のようなものです。(イメージ)
valueの性質はローカルなものとして、クラスコンポーネントを使ってstateを定義します。
ついでにrenderされるマークアップも用意します。

※Hooksはこの記事ではスルーします

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

コンポーネントのコーディングが仰々しく面倒に思いますよね?
でも、拡張機能のスニペットを使えば楽々です。
コンストラクタはrconstrenderメソッドはrenと入力してください。

続いてクリック処理に移りましょう。メソッド名はincrementと付けておきます。
ここで注意ですが、クラスに所属するメソッド名なのでthisを忘れないでください。

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

まだincrementの中身が書いていないのでもう少し準備をします。

  1. クリックイベントで呼び出すメソッドには、this.hoge = this.hoge.bind(this)というおまじないがコンストラクタに必要です。
  2. メソッドをクラス内に記述します。
import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment() {}

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

ようやく準備が整いました。カウントアップできるメソッドを記述しましょう。
this.state.valueを更新しますが、stateの更新にはsetState()メソッドを使います。
Javaでメンバ変数を直接更新せずにsetterを使うようなルールです。

setState()の書き方は用途によって2通りあります。

// 前のstate値を更新に使わない場合:
// 新しい値をセットしたオブジェクトを引数に渡す
this.setState({ hoge: newValue });

// 前のstate値を更新に使う場合: 
// 前のstateを引数に取り、新しい値をセットしたオブジェクトを返す関数を
// 引数に渡す
this.setState((prevState) => ({ hoge: doFuga(prevState) }));

今回は後者になります。

import React from 'react';
import './App.css';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: 0,
    };
    this.increment = this.increment.bind(this);
  }

  increment() {
    this.setState((prevState) => ({ value: prevState.value + 1 }));
  }

  render() {
    return (
      <div>
        <p>{this.state.value}</p>
        <p>
          <button onClick={this.increment}>Increment</button>
        </p>
      </div>
    );
  }
}

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;

this.setStateってなんだかタイポしそうですね。
でも、sstと入力すれば補完してくれます。

これで無事成功です。

ここで注目すべきは、DOMへの描画部分をわざわざ2回書かなくても良いことです。
値を変える処理の後は反映、また別の処理の後に反映...のような記述をしなくて構いません。
値が変わればDOMも勝手に書き換わってくれます。

素晴らしいと思って頂けましたか?
薄い記事ですが、これを取っ掛かりにReactが普及すれば嬉しく思います。

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

【JSDoc】JavaScriptで型補完する

どうしてもJavaScriptで書かないといけない状況に立たされた時、anyを作らないように開発することが大事になってくる。
そういった時にVSCodeなどに型情報を教えるための手段として、JSDocを用いた方法を紹介する。

注意

型アノテーションを記述するわけではないので、コンパイルエラーを発生させることはできません。
コンパイルエラーを発生させたいのならflow - https://flow.org/などを使う必要があります。

JSDoc の @typeについて

ドキュメント

https://jsdoc.app/tags-type.html

変数宣言(メゾットの宣言)の上にドキュメントを書くと、優秀なIDE上ではそのドキュメントを参照することができます。

Screen Capture_select-area_20200914212023.png

変数宣言では@type、メゾットには@param, @returnで型情報を付けることができます。

Screen Capture_select-area_20200914212345.png

Screen Capture_select-area_20200914212452.png

少しは変数の情報がわかりやすくなったのではないかと思います。

ここで注意ですが、型情報を追加しただけなので、型チェックを行いません。なので以下のようなバグコードを書かないようにしましょう。

Screen Capture_select-area_20200914212114.png

変数aは文字列ですがnumber型であるとの情報をつけたせいで、bの型がnumber型になってしまいました。
実際はstringなので良くないです。

まとめ

やっぱり生jsは書かないほうがいいと思います。

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

Instagramにアップロードされた写真を埋め込みHTML形式で取得してみた

はじめに

Instagramにアップロードされた写真を埋め込みHTML形式で取得してみました。

APIを使うために、Facebook developer にアプリを登録したり、Facebookページを作成したり、Instagramのアカウントをビジネスアカウントに切り替えたりと色々事前準備が必要でした。

トークンの取得方法は下記サイトがすごく丁寧に解説してくれていて、参考にさせていただきました。
https://navymobile.co.jp/instagram-graph-api

今回は、Graph API用のアプリ(開発モード)とoEmbed用のアプリ(ライブモード)2つ作りました。
Facebookにレビューが通ればアプリは一つで実現できると思います。

環境は下記になります。
macOS Catalina 10.15.6
Node.js v14.8.0
(Node.js Library)request 6.14.7

コード

下記、コードになります。
(1) Graph API でアカウントに紐付く投稿のURLを取得
(2) oEmbedでURLを埋め込みHTMLに変換
の流れになります。

APIの仕様は下記を参照しました。

・Graph API
https://developers.facebook.com/docs/instagram-basic-display-api/reference/user

・oEmbed
https://developers.facebook.com/docs/instagram/oembed

batch_instagram.js
const request = require('request');

const URL_INSTAGRAM_API='https://graph.facebook.com/v8.0/';
const INSTAGRAM_USERID=process.env.INSTAGRAM_USERID;
const INSTAGRAM_APP_TOKEN=process.env.INSTAGRAM_APP_TOKEN;
const INSTAGRAM_APP_OEMBED_TOKEN=process.env.INSTAGRAM_APP_OEMBED_TOKEN;
const URL_INSTAGRAM_POSTS=URL_INSTAGRAM_API + INSTAGRAM_USERID + '?fields=name,media.limit(99){caption,like_count,media_url,permalink,timestamp,username,comments_count}&access_token=' + INSTAGRAM_APP_TOKEN;
const URL_INSTAGRAM_OEMBED=URL_INSTAGRAM_API + 'instagram_oembed?fields=html,thumbnail_width,type,width&access_token=' + INSTAGRAM_APP_OEMBED_TOKEN + '&url=';

var get_instagram_options_base = {
    url: '',
    method: 'GET',
    json: true
};

var html_data = [];

var get_instagram_options_1 = get_instagram_options_base;
get_instagram_options_1.url = URL_INSTAGRAM_POSTS;
request(get_instagram_options_1, function (error, response, posts) {
    var url_list = [];
    posts.media.data.forEach(data => {
        url_list.push(data.permalink);
    });
    // console.log(url_list);
    urlToHtml_OEmbed(
        url_list,
        function() {
            console.log(html_data);
            return;
        }
    );
});

function urlToHtml_OEmbed(urls, callback) {
    if (urls.length == 0) {
        return callback();
    }
    else
    {
        let url = urls.shift();

        var get_instagram_options_2 = get_instagram_options_base;
        get_instagram_options_2.url = URL_INSTAGRAM_OEMBED + url;
        request(get_instagram_options_2, function (error, response, oembed) {
            html_data.push(oembed.html);
            // console.log(urls.length);
            urlToHtml_OEmbed(
                urls,
                callback
            );
        });
    }
}

実行結果は下記になります。
XXXXXXXXは各自の環境で置き換えて下さい。

% export INSTAGRAM_USERID=XXXXXXXX
% export INSTAGRAM_APP_TOKEN=XXXXXXXX
% export INSTAGRAM_APP_OEMBED_TOKEN=XXXXXXXX
% node batch_instagram.js
[
  '<blockquote class="instagram-media" data-instgrm-captioned data-instgrm-permalink="https://www.instagram.com/p/CEhFobmnEnM/?utm_source=ig_embed&amp;utm_campaign=loading" data-instgrm-version="12" style=" background:#FFF; border:0; border-radius:3px; box-shadow:0 0 1px 0 rgba(0,0,0,0.5),0 1px 10px 0 rgba(0,0,0,0.15); margin: 1px; max-width:658px; min-width:326px; padding:0; width:99.375%; width:-webkit-calc(100% - 2px); width:calc(100% - 2px);"><div style="padding:16px;"> <a href="https://www.instagram.com/p/CEhFobmnEnM/?utm_source=ig_embed&amp;utm_campaign=loading" style=" background:#FFFFFF; line-height:0; padding:0 0; text-align:center; text-decoration:none; width:100%;" target="_blank"> <div style=" display: flex; flex-direction: row; align-items: center;"> <div style="background-color: #F4F4F4; border-radius: 50%; flex-grow: 0; height: 40px; margin-right: 14px; width: 40px;"></div> <div style="display: flex; flex-direction: column; flex-grow: 1; justify-content: center;"> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; margin-bottom: 6px; width: 100px;"></div> <div style=" background-color: #F4F4F4; border-radius: 4px; flex-grow: 0; height: 14px; width: 60px;"></div></div></div><div style="padding: 19% 0;"></div> <div style="display:block; height:50px; margin:0 auto 12px; width:50px;"><svg width="50px" height="50px" viewBox="0 0 60 60" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink"><g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"><g transform="translate(-511.000000, -20.000000)" fill="#000000"><g><path d="M556.869,30.41 C554.814,30.41 553.148,32.076 553.148,34.131 C553.148,36.186 554.814,37.852 556.869,37.852 C558.924,37.852 560.59,36.186 560.59,34.131 C560.59,32.076 558.924,30.41 556.869,30.41 M541,60.657 C535.114,60.657 530.342,55.887 530.342,50 C530.342,44.114 535.114,39.342 541,39.342 C546.887,39.342 551.658,44.114 551.658,50 C551.658,55.887 546.887,60.657 541,60.657 M541,33.886 C532.1,33.886 524.886,41.1 524.886,50 C524.886,58.899 532.1,66.113 541,66.113 C549.9,66.113 557.115,58.899 557.115,50 C557.115,41.1 549.9,33.886 541,33.886 M565.378,62.101 C565.244,65.022 564.756,66.606 564.346,67.663 C563.803,69.06 

〜(中略)〜

utm_source=ig_embed&amp;utm_campaign=loading" style=" color:#c9c8cd; font-family:Arial,sans-serif; font-size:14px; font-style:normal; font-weight:normal; line-height:17px;" target="_blank"> ma sa</a> (@mamemame_s) on <time style=" font-family:Arial,sans-serif; font-size:14px; line-height:17px;" datetime="2016-08-13T10:54:00+00:00">Aug 13, 2016 at 3:54am PDT</time></p></div></blockquote>\n' +
    '<script async src="//platform.instagram.com/en_US/embeds.js"></script>'
]

以上です。

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

tsxのコードブロックはtypescriptではなくtsxと書こう

概要

今回はQiitaのコードブロックのハイライトのお話しです。```の後にプログラミング言語などをtypescriptのように入力するとシンタックスハイライトのcssがあたる仕様になっていますが、ここにはプログラミング言語以外にtsxなどが指定できるようになっていて、typescriptと指定した場合と比べて、以下のようにhtmlタグ部分がシンタックスエラーの表示になってしまうのを防ぐことができます。

BAD: ```typescript

const Typescript = <div>typescript</div>

GOOD: ```tsx

const TSX = <div>tsx</div>

ちなみに

これは、javascript / jsxでも同様です。

BAD: ```javascript

const Javascript = <div>javascript</div>

GOOD: ```jsx

const JSX = <div>jsx</div>

ほんの少しの気遣いでコードブロックが見やすくきれいになります。ぜひ参考にしてください。

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

一部分が重複している2つの配列の、差分を取得する(JavaScript)

一部分が重複している配列の差分を取得します(JavaScript)

sample.rb
function arr_diff (a1, a2) {

    var a = [], diff = [];

    for (var i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (var i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (var k in a) {
        diff.push(k);
    }

    return diff;
}

console.log(arr_diff(['a', 'b'], ['a', 'b', 'c', 'd']));
console.log(arr_diff("abcd", "abcde"));
console.log(arr_diff("zxc", "zxc"));

引用元では他の方法も記載されているようでした。

引用元
https://stackoverflow.com/questions/1187518/how-to-get-the-difference-between-two-arrays-in-javascript

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

配列の重複削除(バニラJS)

生JavaScriptを使って配列から重複を削除する

qiita.rb
var fruits  = ['りんご', 'バナナ', 'りんご', 'バナナ', 'パイナップル', 'スイカ', 'りんご', 'バナナ'];
var deduped = Array.from(new Set(fruits));

console.log(deduped);  // -> ["りんご", "バナナ", "パイナップル", "スイカ"]

引用元
https://gomakethings.com/removing-duplicates-from-an-array-with-the-vanilla-js-set-object/

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

IMI住所変換コンポーネントを魔改造して昔の地名を検索できるようにしてみた

  1. IMI住所変換コンポーネントでいろんな住所を正規化してみた
  2. IMI住所変換コンポーネントを改造してリバースジオコーディングに対応してみた
    のシリーズ記事です。

今回は、IMI住所変換コンポーネントをさらに改造して、昔の地名も検索できるようにしました。

imi-enrichment-address-plus
https://github.com/uedayou/imi-enrichment-address-plus

昔の地名の検索

昔の地名のデータソースとして、大学共同利用機関法人 人間文化研究機構が公開する歴史地名データを利用利用しました。

現在の住所と同じくLevelDBに格納し、緯度経度による逆ジオコーディング検索にも対応しました。

これで、imi-enrichment-address-plus

  • 現在の住所
    • 正規化
    • 緯度経度で検索(逆ジオコーディング)
  • 昔の地名
    • 部分一致検索
    • 緯度経度で検索(逆ジオコーディング)

の4つの検索が可能になりました。

検索方法

この記事では上記4つの検索のうち、昔の地名の部分一致検索と逆ジオコーディング検索の利用方法を紹介します。

現在の住所の正規化については
IMI住所変換コンポーネントでいろんな住所を正規化してみた

現在の住所の逆ジオコーディングは
IMI住所変換コンポーネントを改造してリバースジオコーディングに対応してみた

もしくはimi-enrichment-address-plusのREADME.mdを見てください。

部分一致検索

最も簡単に試す方法はコマンドラインインタフェースでの検索です。

まず、imi-enrichment-address-plusをグローバルにインストールします。

インストールコマンド
$ npm install -g https://github.com/uedayou/imi-enrichment-address-plus/releases/download/v1.1.2/imi-enrichment-address-plus-1.1.2.tgz

これでimi-enrichment-address-plusコマンドが使えるようになるはずです。
通常の住所正規化は-sオプションを使います。

住所正規化コマンド
$ imi-enrichment-address-plus -s 永田町

昔の地名を検索するときは、-s とともに --old オプションをつけてください。
住所正規化は該当する1件を返しますが、この検索では文字数が近い最大10件が出力されます。

昔の地名の部分一致コマンド
$ imi-enrichment-address-plus -s 永田町 --old

例えば、上記を実行すると、以下のような結果が出力されます。

昔の地名での検索結果
{
  "@context": "https://imi.go.jp/ns/core/context.jsonld",
  "場所": [
    {
      "@type": "場所型",
      "住所": [
        {
          "@type": "住所型",
          "種別": "歴史地名データ",
          "ID": "10033625",
          "町名": "永田町",
          "説明": "「大日本地名辞書」6巻 274頁",
          "都道府県": "武蔵",
          "都道府県コード": "594",
          "市区町村": "麹町区",
          "市区町村コード": "797"
        },
        {
          "@type": "住所型",
          "表記": "東京都千代田区永田町一丁目",
          "都道府県": "東京都",
          "都道府県コード": "http://data.e-stat.go.jp/lod/sac/C13000",
          "市区町村": "千代田区",
          "市区町村コード": "http://data.e-stat.go.jp/lod/sac/C13101",
          "町名": "永田町",
          "丁目": "1",
          "種別": "位置参照情報"
        }
      ],
      "地理座標": [
        {
          "@type": "座標型",
          "緯度": "35.676388",
          "経度": "139.746388"
        }
      ]
    },
    ...
  ]
}

検索結果には、住所オブジェクトが2つあり、"種別": "歴史地名データ" であるほうが昔の地名、"種別": "位置参照情報"のほうが逆ジオコーディングにより検索された最も近い現在の住所となります。
地理座標からは緯度経度も得られます。

緯度経度で検索(逆ジオコーディング検索)

部分一致と同じく、通常の逆ジオコーディング検索に--oldつけることで検索対象が昔の地名になります。

現在の住所の逆ジオコーディング検索
$ imi-enrichment-address-plus --lat 35.675551 --lng 139.750413
昔の地名の逆ジオコーディング検索
$ imi-enrichment-address-plus --lat 35.675551 --lng 139.750413 --old

コマンドラインインタフェース以外の使い方

上記で説明したコマンドラインインタフェース以外の使い方として、Web APIとしての利用と、Nodeプログラム上で利用できます。

それぞれの使い方については、imi-enrichment-address-plusのREADME.mdを参照してください。

昔の地名のデータの中身

歴史地名データによると以下の資料をもとに作成されたデータだそうです。

資料名 説明
大日本地名辞書 大日本地名辞書は、吉田東伍(1864~1918)が編纂した日本で最初の本格的な地名辞書で、明治33年に初版が発行されました。「歴史地名辞書データ」には、北海道から沖縄(琉球)の53,528件の地名が収録されています。
延喜式神名帳 延喜式神名帳は、「官社」に指定された神社の一覧であり、延長5年(927年)に編纂されました。これに記載されている神社(式内社)全2,861社のうち、2,842社の位置情報が「歴史地名辞書データ」に収録されました。なお、比定された位置は、必ずしも編纂当時の位置とは限りません。
旧5万分の1地形図 日本ではじめて精密測量に基づいて作製された5万分の1地形図に含まれる地名252,544件とその緯度・経度が「歴史地名辞書データ」に収録されました。本データの作成に当たっては、国土地理院長の承認を得ています(承認番号 平成30情使、第12号)。対象となった図幅は1,343枚で、明治29年から昭和10年に測量されたものです(一部、例外あり)。なお、緯度・経度は、当時の測地系から世界測地系に変換されています。

これによれば、明治時代以前の地名であることがわかります。
上記でも説明しましたが、これら昔の地名に該当する現在の住所があらかじめ割り振っていますので、過去と現在を地理的につなげるような使い方ができると思います。

本モジュールと同じような機能を提供するWebサービスも公開されています。

歴史地名辞書の検索
http://www.eri.u-tokyo.ac.jp/people/ykano/gazetteer/

こちらは今昔マップなどの複数の外部サービスと連携してますし、いくつかの地名や位置を検索したい場合はこちらを利用したほうが良いと思います。

本モジュールはすべてローカル環境で検索を行うので、大量の検索したいデータがある場合、高速に処理が行えることが利点の一つで、自身のサービスに組み込みたい場合にも利用しやすいと思います。

住所・地名周りではかなり便利なツールになったと思いますので、是非活用してもらえればと思います。

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

カウントダウン処理でawaitとasyncの使い方を学ぶ

async/awaitとは

非同期の処理を同期的に書くために使うことは大体の人が知っていると思います。
しかしそれをいざ使ってと言われると私のような初心者は困ってしまいます。
そんな人達にのためにこの記事を書きました。
カウントダウン処理のコードを書きながらawait/asyncの使い方を学んでいきます。

したいこと(目標)

カウントダウン処理ををawait/asyncを使って実装します。
具体的には以下のようにコンソールで表示できるようにします。
start, 5, 4, 3, 2, 1, next

プラン

これからやることは
- start関数を作る
- next関数を作る
- countdown関数を作る
- それぞれが意図したとおりの順番に動くように調整する
です。

start関数とnext関数を作る

コンソールに文字を表示するだけなので、とても簡単です。

console.log("start");
//この間にカウントダウンの関数を入れたい
console.log("next");

結果

このままだとイマイチなので関数として呼び出せるようにします。

//all関数を実行する
all();
//goとnextの関数をまとる関数を作る
function all() {
  start();
  //この間にカウントダウンの関数を入れたい
  next();
}

function start() {
  console.log("start");
}

function next() {
  console.log("next");
}

結果

カウントダウン関数を作る

とりあえずsetTimeoutを使って見る

今回はsetTimeoutを使用してつくります。
とりあえず1秒後にカウントダウンとコンソールで表示されるようにします。

function countdown() {
    setTimeout(() => {
    console.log("countdown");
  }, 1000)
}

結果

今のままでは結果が以下のようになります。

"start"
"next"
"countdown"

async/awaitを使って同期的な処理にする

start, countdown, nextとなって欲しいのでここでようやくasync/awaitを使います。

async function all() {
  start();
  await countdown();
  next();
}

async/awaitはpromiseが返ってくる必要がある!

しかし、これではまだ駄目です。
単純にasync/awaitをつければいいわけではありません。(私はそう思っていました。)
async/awaitを使うにはpromiseが返ってくるようにする必要があります。
そのために、度のタイミングでpromiseが返ってくるかをcountdown関数に書き込みます。

function countdown() {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log("countdown");
      resolve() //1秒後に”countdown”が出たらresolve状態になるという合図
    }, 1000)
  })
}

結果

これでコンソールに正しい順番で表示されます。

"start"
"countdown"
"next"

Promiseとasyncの関係はこちらを参照してください。

カウントダウンされるようにコードを書く

続いて4,3,2,1,0とカウントダウンされるように処理します。
ここからは少しややこしくなります。

all();

async function all() {
  start();
  await countdown(5); //secの初期値を5にしておく
  next();
}

function start() {
  console.log("start");
}

function next() {
  console.log("next");
}

function countdown(sec) {
  return new Promise(resolve => {
    console.log(sec)
    sec -= 1 //secの値を1ずつ減らしていく
    setTimeout(() => {
      countdown(sec); //1秒毎にcountdownが何度も呼び出される処理
      resolve()
    }, 1000)
  })
}

結果

こうすると値は5,4,3,2,1となっていきます。

clearTimeoutを使ってsetTimeoutの処理を止める

しかし、これでは0以下にもどんどんと値が続いてしまうのでclearTimeoutを使ってsecの値が0になったら処理が止まるようにします。

function countdown(sec) {
  return new Promise(resolve => {
    console.log(sec)
    sec -= 1
    const timeId = setTimeout(() => {
      countdown(sec);
      resolve();
    }, 1000)
    if(sec === 0) { //secの値が0になったら処理
        clearTimeout(timeId);
    }
  })
}

結果

0で止まるようにありましたが、このままでは以下の通りカウントダウンの途中で次の処理が行われてしまいます。

"start"
5
4
"next"
3
2
1

再びasync/awaitの登場

ここでの問題はcountdown関数が一度回ったあと(secの値が5から4に変わる時)next関数が実行されることにあるようです。
setTimeoutは非同期を行うための処理です。なのでsetTimeoutを同期的な処理に変える必要があります。そのためにここでまたasync/awaitが必要になってきます。

function countdown(sec) {
  return new Promise(resolve => {
    console.log(sec);
    sec -= 1;
    const timeId = setTimeout(async () => {
      await countdown(sec);
      resolve();
    }, 1000)
    if (sec === 0) {
      clearTimeout(timeId);
    }
  })
}

とするとsetTimeoutの処理を一回ごとに同期的な処理にしてくれます。(1秒ごとにresolveが返ってくるまで待つということ)

結果

コンソールでは以下のように表示されます。

"start"
5
4
3
2
1

今度はカウントが1まで言っているのにnext関数が呼び出されていません。

resolveが呼び出されないと次の処理にはいけない!

これはsecが0になったときにresolveが返っていないので、次の処理が行われないためです。
なのでresolveを追加すればOKのハズです。

function countdown(sec) {
  return new Promise(resolve => {
    console.log(sec)
    sec -= 1
    const timeId = setTimeout(async () => {
      await countdown(sec);
      resolve();
    }, 1000)
    if (sec === 0) {
      clearTimeout(timeId);
      resolve(); ///このタイミングでresolveがかえるようにする
    }
  })
}

結果

こうすることで意図したとおりの動作をしてくれます。

"start"
5
4
3
2
1
"next"

まとめ

ながながと解説してきましたが、これで終わりです。
単純なカウントダウンを作るだけなら特に困らなかったと思いますが、それを前後別の動作と組み合わせるとなかなかややこしいなと思ったのでまとめてみました。
ポイントは"async/awaitだけではなくresolveが返ってくるタイミングを考える"です。
非同期の処理を同期的な処理にするにはasync/awaitが必要ですが、それだけではなく、いつまで処理を待てばいいのかを教える「resolveを返す」という処理をセットで考える必要があります。
特にsetTimeoutのなかにasync/awaitを使うという発想がなかったので備忘録を兼ねて記事にしてみました。
皆さんのお役に立てば幸いです

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

Rails6で非同期処理を実装する際、コンソールでUncaught ReferenceError: $ is not definedというエラーが出た時の対処法

はじめに

今回は私がオリジナルアプリの非同期処理のいいね機能を作成中にハマったエラーの解決方法を書かせて頂きます。
今回ご紹介するこちらの解決法は他に記事がなく(私が見つけられなかっただけかもしれませんが)、私自身かなり苦労しました。
なので、この記事がRails6での非同期処理の実装にお困りの方の助けになれば幸いです。

バージョン

Rails6
(Rails5の方は対象外となります。)

前提

JQueryの導入が完了していることを前提とします。

エラー内容

Console.
VM108:1 Uncaught ReferenceError: $ is not defined
    at <anonymous>:1:13
    at processResponse (rails-ujs.js:283)
    at rails-ujs.js:196
    at XMLHttpRequest.xhr.onreadystatechange (rails-ujs.js:264)

このエラー文の内容としては
create.js.erbに書いてあるJQueryのコードが読み込めませんよ」という内容です。

解決法

JQueryを読み込ませるにはjavascript/packs/application.jsに下記の記述をします。

application.js
window.$ = $;

これでJQueryをグローバルに使用できるようになり、
js.erbファイルでもJQueryを読み込むことができるようになります。

以上です。

いいね機能を作る際のコントローラやビューやルーティングのコードはたくさんの方が投稿してくれていますので
そちらをご覧いただければと思います。

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

さくらvpsでnode.jsでSocket.ioする

Node.jsインストール

さくらVPSでNode.jsが動く環境を作ってみた - Qiita

curl -L git.io/nodebrew | perl - setup
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
source ~/.bash_profile
nodebrew install-binary stable
nodebrew use stable
node -v
v14.10.1

Socket.ioインストール

npm install socket.io
npm -v
6.14.8

Node.jsでHTTPSサーバ(https://〜)

node.jsによるHTTPSサーバの作り方 - Node.js/JavaScript入門

var https = require('https');
var fs = require('fs');
var ssl_server_key = 'server_key.pem';
var ssl_server_crt = 'server_crt.pem';
var port = 8443;

var options = {
        key: fs.readFileSync(ssl_server_key),
        cert: fs.readFileSync(ssl_server_crt)
};

Let's EncryptのSSL証明書などの場所 - nwtgck / Ryo Ota

証明書: /etc/letsencrypt/live/ドメイン名/fullchain.pem
秘密鍵: /etc/letsencrypt/live/ドメイン名/privkey.pem

※サーバを立ち上げるときは

sudo node saver

としないと証明書等が読み込めないので注意

テスト用のコンテンツ

Node.jsとSocket.IOによるPCとスマホブラウザのペアリングデモ - ICS MEDIA
ここのソースを丸ごといただいてごにょごにょと・・・

サーバとクライントでポートが違う場合

<script src="https://planet-ape.net:5000/socket.io/socket.io.js"></script>

 socket.io.jsを読み込むときにポート指定

// サーバーに接続
//var socket = io.connect(location.origin);
var socket = io.connect("https://planet-ape.net:5000");

connectするときもポート指定

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

【JavaScript】再帰処理でJSONの階層を掘り進めて末端の値を変更したい

あらすじ

むかしむかし(先週)あるところに、若いプログラマーがおったそうな。
彼のいるプロジェクトには、大事な情報が詰まった「おしながき」という膨大なJSONファイルがあったそうな。

ある日、プログラマは上司にこう言われた。

「OO.XX.OO.XX.OO.XX」という文字列で階層が与えられるから、「おしながき」のその階層の値を、これまた与えられた値に変更して、新しい別のJSONファイルとして出力してほしい。

はてさて、プログラマはこの先、どうなりますことやら。

(この物語は、2割くらいフィクションです)

指令の詳細

おしながきには、サービスで用いる基準値や名前など、大量のデータが入っています。また、そのデータ量もさることながら、階層も深く、多少浅いものから、かなり深いものまでマチマチです。

今回は、そんなおしながきをベースにしたテストデータを作って欲しいという指示を受けました。おしながきの中の、指定された階層の値のみを、テスト値に変更し、別ファイルとして出力しろというものです。

指定に用いられる情報は、以下の条件を満たします。

  • 指定で与えられるデータの形式は(ID): { {"layer": (string), "value":(any)} }の連想配列
  • 指定で与えられるデータは複数
  • 階層情報はドット区切り
  • 階層情報は必ず末端
  • 階層が「*」の場合は、その階層は配列

おしながきの例

oshinagaki.json
{
 "おしながき": {
  "メイン": {
   "焼き鳥": {
    [
     {"品名": "カワ", "味付け": ["タレ", "塩"]},
     {"品名": "モモ", "味付け": ["タレ", "塩"]},
     ...
    ]
   }
  },
  "サブ": {...},
  "ドリンク" {...},
  ...
 }
}

テスト値情報の例

testValueInfo.js
var testValueInfo = {
 "0001": {
  "layer": "おしながき.メイン.焼き鳥.*.味付け.*", "value": ["", ""]
 },
 "0002": {
  ...
 },
 ...
}

例を見て分かる通り、配列とオブジェクトが複雑に入り混じったJSONを掘り進めるのは簡単ではありませんでした。

軽く計画

この指示を受け、頭の中に軽く浮かんだ流れは以下の通りです。

テスト値情報1つのIDの、階層を示すドット区切りの文字列を配列に変換する。

配列に基づいて再帰的におしながきを探索していき、最深部まで進める
現時点の階層が配列の場合はfor処理を使い、配列要素ごとに掘り進める

末端の値をテスト値に変更し、末端ではテスト値を、それ以外ではJSONオブジェクトを再帰的に返していく。

再帰処理が終わった後は、元のおしながきに返り値を代入する。

次のIDへ

詳細に関しては後述で説明するとします。
上記より計算量が少ない、スマートなアルゴリズムもあるとは思います。例えば、次のテスト値情報を見た時、共通しているディレクトリ戻って次の探索を行う...などが考えられますが、今回はシンプルで分かりやすい方法にします。

実装

階層情報文字列を配列に変換する

JavaScriptには、split()という便利なメソッドがあります。これは、引数で与えられた文字(複数文字可)を区切りとし、文字列を分割して配列にしてくれるスグレモノです。

sample.js
var str = "これ・それ・あれ・どれ";

var array = str.split("");

array.forEach(function(item, index) {
    console.log(index + ":" + item + "\n");
})
0:これ
1:それ
2:あれ
3:どれ

今回はこれに加えて、配列の末尾にテスト値を付け足します。
さらに、指定情報をforEachでループしながら、1回1回頭から探索することにします。

sample.js
//どこからかJSONを取得する
var json = getJson();

// testValueInfo:全ての指定情報が記された連想配列
// {
//    (id): {
//        layer: (階層情報),
//        value: (テスト値)
//    }
// }
testValueInfo.forEach(info, index){
    // 階層情報&テスト値を入れる配列
    var layerArray;

    // layerArrayに階層情報を格納
    layerArray = info.layer.split(".");

    // layerArrayの末尾にtestValueを追加
    layerArray.push(info.value);

    // JSONを探索して値を更新する関数(これから定義)
    json = digJson(json, layerArray);
}

階層情報にテスト値を加えた理由は、再帰処理中はずっとテスト値が不変なので、いちいち引数に与える必要はないと考えたからです。

再帰的におしながきを探索する

処理のおおまかな流れは以下のようになります。

digJson()
// JSONを掘り進める関数
// 引数1:JSON。再帰が進むごとに深くなり、小さくなる
// 引数2:階層情報&テスト値の配列
function digJson(json, layerArray){
    // 現在いる階層
    var currentLayer = layerArray[0];
    // それより深い階層(配列)
    // slice()で先頭要素を除外
    var deeperLayers = layerArray.slice(1);

    // 末端だったらホゲホゲ
    // 配列だったらフゴフゴ

    // 自分より深い階層で更新されたJSONを代入(再帰)
    json[currentLayer] = digJson(json[currentLayer], deeperLayers);

    // 自分自身を返却。1つ上の階層に代入される
    return json;
}

再帰処理はマトリョーシカ人形に例えられることがよくありますが、今回はJSONということで、まさにマトリョーシカです。

親子のように例えるならば、子のJSONに伝言を頼み、結果が返ってくるのを待ちます。末端の子は値を変更して親に返事をし、今度は子が親に伝言を頼み、子の役目は終了していきます。最も大きな親まで伝言が届いたとき、その親が持っているJSONはテスト値が埋め込まれたおしながき全体になっているのです。

「配列をスライスしてJSONを深くするだけなら、再帰じゃなくてforEachで良くない?」とも思いましたが、JSONの中に配列もあり、それがどこにあって何個出てくるのかが非固定なので、このような方法にしました。
また、「配列の場合は"*"を入れる」という独自のフォーマットを採用していることもあり、ライブラリなども使えなく、自前で処理を組むしかなかったように思います。

currentLayerが"*"(配列)のとき

このときはforEachを使って、要素ごとに返却を待ちます

先ほどのように親子で例えるならば、子が三つ子や四つ子などの場合、まず長男に伝言を頼み、長男の返事を待ってから次男に伝言を頼み、次男の返事を待ってから...といった具合です。

// 現階層が配列の場合
if(currentLayer === "*"){
    // 要素ごとにdigJson()を実行
    json[currentLayer].forEach(data, index){
        json[currentLayer] = digJson(data, deeperLayer);
    }
}
// 配列ではない時
else{
    json[currentLayer] = digJson(json[currentLayer], deeperLayers);
}

階層の末端に到達したとき

階層の末端では、引数の「json」にはJSONオブジェクトではなく、単体の値もしくは配列が入っています。(少々ややこしいですが)
末端の子には、jsonにテスト値を代入してもらい、それを親に渡します。親はそれを使って自分の持っているJSONオブジェクトを更新し、そのまた親へ渡す...というのをリレーしていきます。

if(layerArray.length > 2){
    // 末端ではない時の処理
}
// 末端の時
else{
    var testValue = layerArray[1];

    // 末端の値が配列の時
    if(currentLayer === "*"){
        // 配列の要素を全てテスト値に更新
        json.forEach(function(data, index) {
            json[index] = testValue;
        })
    }
    // 配列ではない時
    else {
        json = testValue;
    }
}

digJson()の全容

これらの処理をひとつにまとめ、digJson関数の完成です。

digJson()
// JSONを掘り進める関数
// 引数1:JSON。再帰が進むごとに深くなり、小さくなる
// 引数2:階層情報&テスト値の配列
function digJson(json, layerArray){
    // 現在いる階層
    var currentLayer = layerArray[0];
    // それより深い階層(配列)
    // slice()で先頭要素を除外
    var deeperLayers = layerArray.slice(1);

    // 末端ではない時
    if(layerArray.length > 2){
        // 現階層が配列の場合
        if(currentLayer === "*"){
            // 要素ごとにdigJson()を実行
            json[currentLayer].forEach(data, index){
                json[currentLayer] = digJson(data, deeperLayer);
            }
        }
        // 配列ではない時
        else{
            json[currentLayer] = digJson(json[currentLayer], deeperLayers);
        }
    }
    // 末端の時
    else{
        var testValue = layerArray[1];

        // 末端の値が配列の時
        if(currentLayer === "*"){
            // 配列の要素を全てテスト値に更新
            json.forEach(function(data, index) {
                json[index] = testValue;
            })
        }
        // 配列ではない時
        else {
            json = testValue;
        }
    }

    // 自分自身を返却。1つ上の階層に代入される
    return json;
}

if(currentLayer === "*")が2回出てくることに少し違和感がありますが、仕方ない...と思います。もうちょっとスマートなやり方がある気がしないでもないでもないですが...気にしないことにします。

感想

再帰は難しい!!

理由としては、forやwhileなどのループと違ってメソッドなので、引数・ローカル変数・返り値を適切にしなければならない点が原因だと思います。コードだけ見れば簡素ですが、自分のような若造にとってはなかなか骨のあるミッションでした。再帰を利用するというのを比較的早く思い浮かんだのが幸いでした。

実際の業務ではもう少し複雑な条件で作っていますが、それはまた別のお話...。

おまけ

実際の業務ではバグ対策として、指定された階層が見つからない場合は何もしない(自分自身をreturnする)という処理を入れているのですが、その際に得た知識です。

var value = null;

value === undefined; // false
value ==  undefined; // true

このおかげでちょっと困りました。おそまつ。

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

フロントエンドのアーキテクチャを考える時に意識していること

自分がフロントエンドのアーキテクチャを考える時に、特に意識していることについてまとめてみました。
改善するべき点が多いと思っていますが、自分の考えを整理する意味で書き残したいと思います。

ここで言う「アーキテクチャ」とは?

この記事では、アーキテクチャについて主にコード間の依存関係の観点で考えています。
「なぜ依存関係なのか」については、次の意識しているポイントで触れていきます。

意識しているポイント

捨てやすくする

  • 書いたコードを捨てやすいようなアーキテクチャを目指したいと思っています。
    • なぜなら、最初から良い設計はできないからです。(まれにできる人もいますが、少なくとも自分はできないです)
    • 開発を重ねて理解が深まることで、より良い設計が見つかります。
    • 良い設計が見つかった時に、既存のコードの修正・削除が必要になりますが、それができないと実現(実装)できないことになってしまいます。
    • コードが捨てやすければ、容易に書き直しができます。
  • 捨てやすくするには、コード修正時の影響範囲の最小化・把握が大切だと思っています。
    • 影響範囲にダイレクトに効いてくるのはコード間の依存関係です。

依存は単一方向になるようにする

  • 依存を単一方向に保つことで、コード修正の影響範囲を小さく保つことができます。
    • その結果、影響範囲を容易に把握できるようになります。コードの変更に強くなります。

外部 API に依存するレイヤーを制限する

  • 外部 API にアクセスするのは特定箇所のコードだけに制限するようにします。
  • これにより、API の仕様変更があったとしても、その箇所のコードを修正するだけで済むようになります。
    • 外部 API は自分たちでコントロールできない領域なので、ここに強く依存すると意図せぬ大改修が発生しかねないです。
    • なのでこれ、外部 API に限った話ではないです。「自分たちでコントロールできないものに依存しすぎるな」ということが言いたいです。

↑を意識して考えたアーキテクチャ例

いくつかのレイヤーに分けています。
レイヤー間の依存関係にはルールがあります。

image.png

UI

  • 所謂 View です。
  • 画面を表示する責務を持ちます。

Application Config

  • アプリケーションやフレームワークの設定情報に責務を持ちます。
  • 例えば、Nuxt.js や Next.js の設定などです。
  • UI 以外に依存します。また、Business Logic には依存しないことが望ましいです。(正直あまり整理できていない...)

Business Logic

  • 所謂ビジネスロジックに責務を持ちます。
  • 「ビジネスロジック」についてはググってもらえたら色々情報が出てくると思うのでここでは触れません。
  • UI 以外に依存します。また、Application Config には依存しないことが望ましいです。(ここもあまり整理できていない...)

Interface Adapters

  • 外部 API へのアクセスに責務を持ちます。
  • 外部 API へのリクエストを発行したり、取得データを(Entities で定義されたインタフェースに)加工します。
  • Utilities と Entities に依存します。
  • また、External API に直接依存はせず、インタフェースを介します。(依存関係の逆転)
    • (理解が正しいかあまり自信がないです...)

Utilities

  • 他のどのレイヤーにも所属しない共通ロジックなどの置き場です。
  • 他のどのレイヤーにも依存しないべきです。ただし、Entities は場合によっては可です。

Entities

  • アプリケーションで扱う対象を定義する責務を持ちます。
  • エンティティ・ドメインモデルなどと呼ばれているものです。
  • 他のどのレイヤーにも依存してはいけません。

External APIs

  • 外部 APIです。(自分たちで管理していないの外の世界)

改善したいと思っている点

  • Business Logic / Application Config / Interface Adapters が混在しがち
    • 複数の責務が1つのファイルに混在しがちになる
    • Nuxt.js を使っていると、store や plugins あたりがカオスになりがち
    • UI レイヤーにもこれらが潜みがちなので、そうならないような案を考えたい
  • フレームワークに依存しても良いレイヤーの整理
    • 何も意識せずに開発すると、コードのあらゆる箇所で Nuxt.js や Next.js への依存が発生してしまう
  • 定数を定義する場所が曖昧
    • 定数を定義する場所が曖昧なので、ルールがほしい
  • Utilities が割れ窓になりそう
    • 比較的何でも置けてしまうので、カオスにならないようなルールがほしい

参考にした書籍・ドキュメント

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

validate()メソッドを使って自動で作成されたパスを使用しなくする(Nuxt.js)

なぜ必要か

Nuxt.jsでは/pagesディレクトリ内にvueファイルを作成すると自動でパスを作成してくれる機能がある。
しかし、pages/user/settingsみたいにuserパスを使わずsettingsパスのみを使いたい場合にもuserパスが使われてしまうので、使用できないようにする。

やり方

使用したくないパスのファイルに以下を記述

/pages/user.vue
<script>
export default {
  // 追加
  validate ({ route }) {
    return route.name !== 'user'
  }
}
</script>

解説

validate() はパスのアクセスを管理するメソッド。このメソッドによって使用したくないパスの管理ができる。

route.name !== 'user' はルート名が’user’ではない時にパスを通す。

これで/userにアクセスしても404エラーが表示される

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

JavaScript while文

 javascriptのwhile文の書き方です。

while(条件式) {
    繰り返し実行する処理。条件式がtrueの間繰り返される
}

 while文では条件式がtrueの間、繰り返し処理が実行されます。

  let i = 1;
  while(i <= 10) {
    console.log(i);
    i += 1;
  }

 このような書き方をすると、変数iが10以下の場合に繰り返し処理が実行されることになります。
console.log(i)でコンソールに数字が表示された後、i += 1;で変数iを再定義しています。繰り返されるごとに変数iに+1される形です。変数iが11になると条件式がfalseになるので、条件式がtrueになる10回目の繰り返しまでで処理は終了になります。

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

特定のページでJavaScriptを動作させる方法

動作環境
Ruby 2.6.5
Rails 6.0.3.2

基本的にJavaScriptは全てのページで発生しているため、JavaScriptを使用していないページでも検証ツールのconsole内でJavaScriptのエラーが発生してしまいます。それが、ようやく解決できたので、投稿してみました。

実装に必要なコード

hoge.js
if (location.pathname.match("hoge")){
  //ここからJavaScriptを書き始める。
}

これでhogeというパスでのみhoge.jsは動作します。

一応解説を入れておくと、location.pathnameにより現在のパスを取得しmatchでhogeと合っているのかを確認しています。

個人的にconsole内のJavaScriptのエラーが気になっていたので、これですっきりしました。

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

【JS学習その②】JavaScriptにおけるスコープ

JS学習シリーズの目的

このシリーズは、私ジャックが学んだJavaScriptのメカニズムについてアウトプットも兼ねて、
皆さんと知識や理解を共有するためのものです。
(理解に間違いがあればご指摘いただけると幸いです)

用語の定義

  • 実行コンテキスト・・・ コードを実行する際の文脈・状況(グローバルコンテキストと関数コンテキスト、evalコンテキストが存在する)
  • コールスタック・・・実行中のコードがたどってきたコンテキストの積み重ね
  • ホイスティング・・・コンテキスト内で宣言した変数や関数の定義をコード実行前にメモリーに配置すること(宣言の巻き上げ)
  • スコープチェーン・・・スコープが複数階層で、連なっている状態

スコープとは

「実行中のコードから値と式を参照できる範囲」

スコープは、実行中のコードからホイスティングされた値や式を参照できる範囲のことをいいます。
ホイスティングされている場所や書き方によって、参照される値や式は変わってきます。

スコープの種類

  • グローバルスコープ
  • スクリプトスコープ
  • 関数スコープ
  • ブロックスコープ
  • モジュールスコープ

上記の5つのスコープ存在します。
モジュールスコープに関しては、モジュールを理解している必要があるので、今回は省略します。

グローバルスコープ

グローバルスコープには、jsファイルの直下に書かれた"var変数"と"functionで宣言された関数"など
があります。
上記の"var変数"と"関数"は、グローバルオブジェクト(windowオブジェクト)の中に格納され、
グローバルスコープは、そのファイル内のどこからでもアクセスできます。
このことから、グローバルオブジェクトそのものがグローバルスコープと言うこともできます。
基本的にグローバルスコープはwindowオブジェクトを省略して記述し、記述方法が次に説明する
スクリプトスコープとほぼ同じなので、スクリプトスコープもまとめてグローバルオブジェクトと呼ばれることもあります。

main.js
var a = 0;
function b() {}

スクリプトスコープ

スクリプトスコープには、jsファイルの直下に書かれた"const定数"や、"let変数"などがあります。

main.js
const a = 0;
let b = 0;

関数スコープ

関数スコープとは、宣言された関数の{}(波括弧)の中のスコープのことを指します。

main.js
function sample() {
    let a = 0;
    console.log(a);
}

sample();

上のコードのように、sample()の中で宣言した変数"a"は、sample()関数内のconsole.log()で扱えます。

main.js
function sample() {
    let a = 0;
}

console.log(a);

しかし、sample()の中で宣言した変数"a"を関数スコープの外で使おうとすると、エラーが出ます。
関数スコープの外なので参照できる範囲の外ということですね。

ブロックスコープ

ブロックスコープは、{}(波括弧)の中のスコープのことを指します。
基本的には、関数スコープと似ているのですが、

  • 前述した関数スコープはブロックスコープの影響を受けない
  • var変数はブロックスコープを無視する

上記に気を付けてください

main.js
{
    let a = 0;
    console.log(a); /*正常に動作*/

    let b = 1;


    function sample() {
        let c = 2;
        console.log(c);
    }

    sample(); /*正常に動作*/

    var d = 3;
}

console.log(b); /*エラー*/
sample(); /*正常に動作*/
console.log(d); /*正常に動作*/

したがって上記のようにコードを書いた場合、コメントした内容の結果になります。

おまけ(varについて)

今回の記事でちょくちょくでてきたvar変数は、グローバル変数といって、様々なスコープを無視して
参照できるので、現在のJavaScriptでは非推奨となっています。
できるだけ、constやletで変数は定義するようにしましょう。

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

【React】ボタンクリックで別のDOM要素のイベントを起動する方法

react-v16

はじめに

ボタンクリックで別のDOM要素のイベントを起動する方法についてです。

Material Uiの<Button />など、あらかじめカスタムされたコンポーネントだと別のDOM要素を紐付けるカスタムは面倒です。
ここではuseRef()を使用し、onClickでDOMの参照に対する操作を行うことで解決します。

※通常は<Form />要素を使用することで複雑な実装なく動作します。

シチュエーション

ボタン(<Button />)と、透明な入力ボックス(<input />)がある
<input type="file" />を使用したファイルアップロードをボタンから行えるようにしたい。

やりたいこと

ボタンをクリックしたら、入力ボックスがクリックされた挙動をさせたい

関数コンポーネント
<Button
  onClick={handleClick}
>

<input
  type="file"
  style={{display: 'none'}}
/>

 

方法

  • React.useRef()を使って、入力ボックス(<input />)の参照を得る
  • onClickしたら、関数内で参照をクリックさせる
関数コンポーネント
const inputRef = React.useRef();

const handleClick = () => inputRef.current.click();

// .....

<Button
  onClick={handleClick}
>

<input
  type="file"
  ref={inputRef}
  style={{display: 'none'}}
/>

まとめ

  • React.useRef()を使うことで、操作したいDOMへの参照を得る
  • onClick内で参照に対する操作を行う

こうすることで、あるボタンから別のDOM要素のイベントを起動できる。

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

【MT7】カスタムフィールドの値によってjsでリダイレクトする

概要

MT7でカスタムフィールドの値によってリダイレクトを行ったときのメモです。
記事によってその記事を見せずに、別ページやトップに飛ばしたい。といった感じです。

PHPが使えないため、jsで処理を入れました。

実装

ページを読み込んだ最初に処理したいので、head内にスクリプトを書きました。
チェックボックスのカスタムフィールドで、チェックが入っていればリダイレクトします。

テンプレートタグ:CFIsRedirect
ベースネーム:cf_is_redirect

index.html
<head>
:
:
  <script type='text/javascript'>
  var status = <MT:CFIsRedirect encode_js="1">;
  if (status == 1) {
    location.href = 'https://example.com';
  }
  </script>
</head>

MTタグの内容をjsで使う場合は、モディファイアencode_js="1"を指定します。
このモディファイアを指定することでjsの文字列の値として使えるようにエンコードしてくれます。

チェックが入っていれば値は1なので、その場合location.herfで指定のURLに飛ばしています。

まとめ

今回の手法は、アナリティクスなどを正確に計測するため、パラメーターやリファラを正しく引き継ぐようなリダイレクトではないので、実際はもう少し処理が必要なようです。

参考

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

順不同な非同期処理を待機して順番どおりに実行する

非同期処理を呼び出された順番どおりに実行するパターンです。processing変数によって、実行時にフラグをたてておいて、それをsetIntervalで監視してよいタイミングになるとsetIntervalを止めて実行します。

非同期処理をそのまま実行する例

index1.js
const data = ['a', 'b', 'c', 'd', 'e'];

const randomInt = function(min, max) {
  return Math.floor( Math.random() * (max + 1 - min) ) + min;
};
const process = name => {
  setTimeout(() => {
    console.log('process:' + name);
  }, randomInt(1000, 3000));
}

data.forEach((value) => {
  process(value)
  console.log(value);
})

// 実行結果
// a
// b
// c
// d
// e
// process:e
// process:d
// process:b
// process:a
// process:c

順不同な非同期処理を待機して順番どおりに実行する例

index2.js
const data = ['a', 'b', 'c', 'd', 'e'];

const randomInt = function(min, max) {
  return Math.floor( Math.random() * (max + 1 - min) ) + min;
};

let processing = false;
const process = name => {
  processing = true;
  setTimeout(() => {
    console.log('process:' + name);
    processing = false;
  }, randomInt(1000, 3000));
}

data.forEach((value) => {
  const intervalId = setInterval(() => {
    if (processing === true) {
      return;
    }
    clearInterval(intervalId);
    process(value);
  }, 50);
  console.log(value);
})

// 実行結果
// a
// b
// c
// d
// e
// process:a
// process:b
// process:c
// process:d
// process:e
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非同期処理を待機して一番最後に呼ばれたものだけ実行する

キー入力に対してインクリメントに動作するAPI呼び出しの待機処理などに使えるパターンです。
setTimeoutで遅延実行させている間に次の呼び出しがあった場合は、clearTimeoutで前回の呼び出しをキャンセルするので、最後に呼ばれたものだけが実行されます。

非同期処理をそのまま実行する例

index1.js
const data = ['a', 'b', 'c', 'd', 'e'];

const randomInt = function(min, max) {
  return Math.floor( Math.random() * (max + 1 - min) ) + min;
};
const process = name => {
  setTimeout(() => {
    console.log('process:' + name);
  }, randomInt(1000, 3000));
}

data.forEach((value) => {
  process(value)
  console.log(value);
})

// 実行結果
// a
// b
// c
// d
// e
// process:e
// process:d
// process:b
// process:a
// process:c

非同期処理を待機して一番最後に呼ばれたものだけ実行する例

index3.js
const data = ['a', 'b', 'c', 'd', 'e'];

const randomInt = function(min, max) {
  return Math.floor( Math.random() * (max + 1 - min) ) + min;
};

const process = name => {
  setTimeout(() => {
    console.log('process:' + name);
  }, randomInt(1000, 3000));
}


let timeoutId;
data.forEach((value) => {
  clearTimeout(timeoutId);
  timeoutId = setTimeout(() => {
    process(value)
  }, 1000)
  console.log(value);
})

// 実行結果
// a
// b
// c
// d
// e
// process:e

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

JSのArrayに「ランダムに要素を返す」メソッドを生やす

メモ。目新しいことは書いてない。

普通にやる

普通にやるとこんな感じ。

function randomSelect(array){
  let index = Math.floor(Math.random() * array.length)
  return array[index]
}

let fruits = ["apple", "orange", "banana"]
console.log(randomSelect(fruits)) // →banana

prototype拡張で書く

個人的にはなんかこの書き方が好きじゃないので、prototypeに直接拡張してみた。

Array.prototype.lot = function(){
  let index = Math.floor(Math.random() * this.length)
  return this[index]
}

let fruits = ["apple", "orange", "banana"]
console.log(fruits.lot()) // →banana

lotはくじという意味。可読性的にはrandomとかrandomSelectとかのほうがいいと思う。

取り出した要素を配列から削除するバージョン。

Array.prototype.pick = function(){
  let index = Math.floor(Math.random() * this.length)
  return this.splice(index,1)[0]
}

let fruits = ["apple", "orange", "banana"]
console.log(fruits.pick()) // →banana
console.log(fruits) // →["apple","orange"]

prototype拡張しても大丈夫な時しか使えないけど、メソッドチェーンぽく使えてちょっと便利……かもしれない。好みの問題かな?
今書いてるやつでこういう処理を頻繁にやるので、導入してみたらちょっといい感じになったよというお話でした。

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

'rgb[a](R, G, B[, A])' を正規表現で処理して、各値をメンバーとしてもつオブジェクトを返す関数。

たとえば、'rgba(220, 20, 60, 0.5)' を放り込めば

{
    red  : 220,
    green: 20,
    blue : 60,
    alpha: 0.5,
}

が返ってくる関数です.

完成コード


TypeScript
rgba.ts
interface RgbaValues {
    red:number,
    green:number,
    blue:number,
    alpha:number
}

const rgbaStrToValues = ( rgba:string ):RgbaValues|void => {
    const realNumPattern = '([+-]?\\d*\\.?\\d+)';
    const rgbaPattern = `rgba?\\(` +
        ` *${ realNumPattern } *, *${ realNumPattern } *,` +
        ` *${ realNumPattern } *(?:, *${ realNumPattern } *)?\\)`;
    const regexp = new RegExp( rgbaPattern );
    const result = regexp.exec( rgba );
    if ( ! result ) { return; }

    const { 1: red, 2: green, 3: blue, 4: alpha } = result;
    if ( ! ( red && green && blue ) ) { return; }

    const { min, max } = Math;
    return {
        red  : max( min( Number( red ), 255 ), 0 ),
        green: max( min( Number( green ), 255 ), 0 ),
        blue : max( min( Number( blue ), 255 ), 0 ),
        alpha: alpha ? max( min( Number( alpha ), 1 ), 0 ) : 1,
    };
};

1



JavaScript
rgba.js
const rgbaStrToValues = function( rgba ) {
    const realNumPattern = '([+-]?\\d*\\.?\\d+)';
    const rgbaPattern = `rgba?\\(` +
        ` *${ realNumPattern } *, *${ realNumPattern } *,` +
        ` *${ realNumPattern } *(?:, *${ realNumPattern } *)?\\)`;
    const regexp = new RegExp( rgbaPattern );
    const result = regexp.exec( rgba );
    if ( ! result ) { return; }

    const { 1: red, 2: green, 3: blue, 4: alpha } = result;
    if ( ! ( red && green && blue ) ) { return; }

    const { min, max } = Math;
    return {
        red  : max( min( Number( red ), 255 ), 0 ),
        green: max( min( Number( green ), 255 ), 0 ),
        blue : max( min( Number( blue ), 255 ), 0 ),
        alpha: alpha ? max( min( Number( alpha ), 1 ), 0 ) : 1,
    };
};


説明

正規表現

'rgba' もしくは 'rgb' にマッチする正規表現は,/rgba?/ なので,'rgba(*)', 'rgb(*)' の両方にマッチする正規表現は,次のようになります2.

/^rgba?\(.*\)$/

'rgb[a](R, G, B[, A])' の各値は,実数3(0 省略可)の正規表現 /([+-]?\d*\.?\d+)/4でマッチさせます. R, G, B は 0~255, A は 0~1 の範囲ですが,ここでは数値の範囲は限定しません.これを加えると次のようになります.

/^rgba?\(([+-]?\d*\.?\d+), ([+-]?\d*\.?\d+), ([+-]?\d*\.?\d+), ([+-]?\d*\.?\d+)\)$/

A 値はオプショナルなので,(?:)(非格納括弧)で囲って ? を後ろにつけます.また,カンマと括弧の内側5にはスペースが 0 以上の任意個数含まれるので,/ *//,/ の前後に入れます. 以下で正規表現は完成です.

/^rgba?\( *([+-]?\d*\.?\d+) *, *([+-]?\d*\.?\d+) *, *([+-]?\d*\.?\d+)(?: *, *([+-]?\d*\.?\d+).*)\)$/

TypeScript / JavaScript

上の完成コードでは,実数部分だけ一旦 realNumPattern に入れてから結合していますが,1 行が長くなってもいいなら,次のように直接正規表現を記述してコメントを付けたほうが分かりやすいかもしれません(文字列型では \ のエスケープが二重になるのがちょっと鬱陶しい……).

const rgbaPattern =
    /^rgba?\( *([+-]?\d*\.?\d+) *, *([+-]?\d*\.?\d+) *, *([+-]?\d*\.?\d+)(?: *, *([+-]?\d*\.?\d+).*)\)$/g;
    // /[+-]?\d*\.?\d+/ は実数

RegExp.prototype.exec( str )MDN は,str が正規表現にマッチしなかった場合は null を,マッチした場合は,正規表現の括弧内にマッチした部分文字列が [1], ...[n] に格納されたオブジェクトを返します. なので,rgb に指定した文字列が正規表現にマッチしなかった場合は,if ( ! result ) { return; }undefined を返すようにしています.

また,TypeScript 4.0.2 の型推論では, この時点で result[1], [2], [3], [4] の型は string になっていますが,実際には string|undefined のはずなので6,一応型ガード的に if ( ! ( red && green && blue ) ) { return; } を入れています7

以上のチェックを通過した場合,red, green, blue を 0~255 の数値型に,alpha を 0~1 の数値型( undefined の場合は 1 )に変換した値をオブジェクトに格納して return します.

あとがき

想定使用例としては,

  1. 不透明度を半分にした 'rgba(*)' を生成する.
  2. RGBAHSLACMYK などに変換する別の関数に放り込む.

などを考えています.今回はとりあえず 1. の用途で使う予定です.

より簡単そうな方法としては,.replace() で括弧内を取得し,.split(',') で各値に分割するという手も考えられますが,個人的には正規表現で文字列全体をマッチさせたほうが安心感があったので,今回の方法をとってみました.

以上です.


  1. rgbaStrToValues() の戻り値の方は,書かなくても OK(つまり RgbaValues インターフェースも不要)ですが,export rgbaStrToValues() する場合, 書いたほうがいいです(eslint で "@typescript-eslint/explicit-module-boundary-types"gitHub を有効にしている場合は,警告が出ます). 

  2. document.getCompuotedStyle()[someColorProperty]MDN の値は(すくなくとも Chrome では)かならず 'rgba(*)' 形式ですが,ElementCSSInlineStyle.style[someColorProperty]MDN の値は 'rgb(*)'形式の場合があります. 

  3. 'rgb[a](R, G, B[, A])' の各値が取りうるデータ型は <number><percentage> ですMDNが,<percentage> はほとんど見たことがないので,とりあえず無視しています(CSSStyleDeclaration[someColorProperty]MDN の値も,rgb[a](<number>, <number>, <number>, <number>) 形式です).なお,rgba 引数に <percentage> を値にもつ rgb[a](R, G, B[, A]) を入れた場合は,regExp にマッチしないため ! result となって,return undefined; となります. 

  4. Cf. 数値とマッチする正規表現 - Qiita.  

  5. 一応括弧の外側にも含みうるので,/ *\(/ として regExp.exec( rgba.trim() ) とすれば,さらに厳密になります. 

  6. この問題は,配列一般に当てはまります.Suggestion: option to include undefined in index signatures · Issue #13778 · microsoft/TypeScript をざっと見たかんじ,仕様どおりでとくに変更される予定もなさそうです. 

  7. inFinite() を使えば,より厳密に,ちゃんと数字と小数点のみの文字列が取れているか確認できますが,そこまでやる必要はないと思います.似たような処理で,もっと正規表現が複雑な場合は,そこまでチェックしたほうがよさそうですが. 

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

JavaScriptの関数について

私たちが普段目にしているWebサイトではたくさんのJavaScriptのコードが記述されている。その中のコードの管理方法としては関数を用いるのが有効的である。今回は、そんな関数についてまとめてみた。

今回まとめること

  1. JavaScriptでの関数定義
  2. 無名関数と即時関数
  3. アロー関数

1.JavaScriptでの関数定義

基本形
qiita.js
function 関数名( 引数 ){
 //関数内の処理
}
戻り値

戻り値とは、最終的に出力される値のことを指す。
JavaScriptでは戻り値をreturnを用いて明示する。

qiita.js
function calc(num1,num2){
 return num1*num2
}

const num1 = 3
const num2 = 4
console.log(calc(num1,num2))

※num1 * num2 の値が出力される。

関数宣言
qiita.js
function 関数名( 引数 ){
 //関数内の処理
}

こちらは冒頭で記述した基本形。

関数式
qiita.js
変数 = function( 引数 ){
 //関数内の処理
}

こちらは関数名を指定しない(常に無名関数となる)
変数に対してfunctionから関数内の処理までを代入する。

関数宣言と関数式との違いとは

まずはコードを書いてみる。

qiita.js
//関数式
const hello = function(){
 console.log('hello')
}

//関数宣言
hello()
function hello(){
 console.log('hello')
}

結論、関数式は呼び出しもとのhello()が先に呼び出され、関数宣言では呼び出しもとのhelloが後から呼ばれる(Rubyの出力と同じ)
つまり、この場合正しく出力されるのは関数宣言となる。

考察

関数宣言はRubyの出力と同じだと記述したが、Rubyは日本人が作成したことから結論を最後にもってきているのではないかと考えた。
逆に関数式は英語と同じで結論を先にもってくる。こういった言語の違いがあるのではないだろうか。

2. 無名関数と即時関数

無名関数

無名関数は関数名なしで関数を定義することができる。
先程ちらっと記述したが、関数式は常に無名関数である。

qiita.js
const calc = function(num1,num2){
  return num1*num2
}

const num1 = 3
const num2 = 4
console.log(calc(num1,num2))
即時関数

関数を定義すると同時に実行される構文。
呼び出しもとが不要で、一つの構成で出力できる。全体を()で囲むといった特徴がある。

qiita.js
// 無名関数
const countNum = function(num) {
  console.log(num)
}
countNum(1)

// 即時関数
(function countNum(num) {
  console.log(num)
})(1)

3. アロー関数

functionの記述を省略し、代わりに ( ) => という記述によって関数を定義する。

qiita.js
// 無名関数
const 変数名 = function(){
  処理
}

// アロー関数
const 変数名 = () => {
  処理
}

このようにより短い記述で関数を定義することが可能となる。

最後に

ここまで記事を読んでいただき、ありがとうございました。

Webアプリケーションのみならず、Webサイトやゲームなど、幅広く利用されているJavaScript。是非使いこなせるようになりたいです。

幅広く利用されているのは、それなりの理由があるからだと思っていて、使いこなすことでプログラミングの幅を広げていきたいと考えています。

今回の記事はここまでです。最後まで読んでいただき、本当にありがとうございました!

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

Vue.jsのcomputedとmethodsの挙動の違い

Vue.jsをいじっていて、何気なく使っているcomputedプロパティですが、methodsでも同じようなことできるよなあと常々感じていました。今回はそのモヤモヤを解消するために、いろいろ調べてみたところ、挙動に決定的な違いがあることが分かったので、今回はこの二つの挙動について、備忘録としてまとめていきたいと思います。

computedとmethodsを用いて似たような挙動をするものを作成

下記のように、v-onディレクティブを用いて、ボタンを押すたびにカウントアップできるアプリを作成しました。それに、computedプロパティとmethodsを用いて、5以下の場合は「5以下」と、5よりも大きくなれば「5より上」と表示されるようにしてみました。

See the Pen QWNxWNp by Yasunari Fujiwara (@yasunari-fujiwara) on CodePen.


コンソールを確認すると、ボタンを押すたびに、methodsもcomputedもそれぞれ一回ずつ呼ばれて処理をしているのが分かります。意図する処理ができているっぽいですが、実際は決定的な違いがあるようです。
違いが分かりやすいように、もう一つ別のボタンを作成して、その挙動をコンソールで確認します。


See the Pen WNwyvRe by Yasunari Fujiwara (@yasunari-fujiwara) on CodePen.


別のカウントアップボタンを押すときの挙動に注目します。コンソールを見ると、ボタンを押すたびにmoreThanFiveMethodが呼び出されているのが分かります。つまり、methodsは、テンプレートの中身が変わり、再描画された瞬間に呼び出されるということです。一方で、computedプロパティは参照先のデータが変わったときのみ、つまりここではthis.numberで指定したnumber変数の中身が変わったときのみ、呼び出されるということです。

computedプロパティとmethodsはどう使い分ければよいか?

computedプロパティとmethodsの決定的な違いとは「呼び出されるのが、データの参照先が変更したときか、テンプレートの中身が変更したときか」というものでした。今回作成したアプリは、カウントアップボタンを押すたびに5より大きいか判定するという処理の回数が多く、かつ参照先のデータに対してのみ処理がしたかったので、computedプロパティがを用いるのが適切でした。そのため、参照するデータ先が、つまり依存関係にあるプロパティが高い頻度で変更される場合にはcomputedプロパティを用いるのが適切だと考えられます。また、反対にmethodsの場合は、それほど頻度が高くなく、クリック時などの一括で処理を行うときに用いるのが適切だと考えられます。

参考サイト

https://dev83.com/vue-computed-methods/
https://www.e-loop.jp/knowledges/1/

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

【React.js】class構文 と fanction構文

react-article-img.png

前書き

Reactを学習していた中で "class構文・fanction構文" を学習しましたので、こちらでアウトプットとして記録いたします。
学習されている方にお役に立てると非常に嬉しいです。

また、コードは Github で公開しているので気になるかたはダウンロードしてみてください。

class構文 と function構文とは

Reactをコーディングする方法として "class構文""fanction構文" があります。
これらの表記は↓になります。

Class構文
import React from 'react';

class 関数名 extends React.Component {
    render(){
        return(
         <React.Fragment>
          処理
         </React.Fragment>
        );
    }
}

export default 関数名;
function構文
import React from 'react';

function 関数名(引数) {
  return (
    <div className="Comment">
     処理
    </div>
  );
}

export default 関数名;

また、function構文にはもう1つ表記方法があります。

arrow関数
import React from 'react';

const 関数名 = (引数) => {

    return(
        <>
        処理
        </>
    )
}

export default 関数名;

こちらは、ES2015(ES6)アロー関数で表記されたものです。

どの構文で書けばいいのか?

業務環境により、構文使用の優先度は異なると思いますが、できるだけなら "function構文のアロー関数" で表記する方が良いです。

その理由は "class構文" よりも "function構文" の方が シンプル に表現できるため。
コーディングをする上では、複雑なコードを書くよりも、シンプルに表記される方が好ましいです。
また、Javascriptの使用は現在では "ES2015(ES6)" が推奨されます。アロー関数は ES2015 に該当するので使っていく方が良いでしょう。

しかし、アロー関数 は全てのブラウザで表示可能な訳ではありません。
現在では大抵のブラウザは対応しますが、古い環境下だと対応していないのでこれは知識に入れましょう。

(アロー関数の動作環境)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

また、次からは MAP配列を使った "class構文" と "function構文" のページを比較します。

class構文で書く

react-img-1.png

ここでは、横並びのコンテンツを "class構文" で書いてみます。
次に、function構文で同じ者を作るので、比較をしてみましょう

Class構文(Language.js)
import React from 'react';

class Language extends React.Component {
    // Übergeben "props" mit Daten als Argument
    render(){
        return(
            <div className='language-item'>
                <div className="language-name">{this.props.name}</div>
                <img
                className='language-image'
                src={this.props.image}
                />
                <div className="language-introduction">{this.props.introduction}</div>
                </div>
        );
    }
}



export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
class構文だとこの処理に "this.props.image" など this を使うのが特徴的です。

Class構文(Language.js)
import React from 'react';
import Language from './Language'
import './App.css';

class Main extends React.Component{
  render(){
    //Datenarray Definition (MAP)
    const languageList = [
      {
        name: 'English',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
      introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
      },
      {
        name: 'Japanish',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
      introduction: 'Diese Sprache wird in Japan gesprochen.'
      },
      {
        name: 'Deutsch',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
      introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
      }
    ];

    return(
      <div>
        <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
        </div>
    );
  }
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Class構文(index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import Main from './Main';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
   <Header />
   <Main />
   <Footer />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

(行っていること)
個別のコンポネートを index.js に記しています。

※こちらでは、cssや他コンポネートは記していません。下記のgithubでコーディングファイルを共有しているので、気になった方はダウンロードをして確認してみてください。

Github
こちらでは、class構文のファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

class構文では "this" や が特徴的です。

では、function構文(アロー関数)で書いてみます。

function構文(アロー関数)で書く

Function構文(Main.js)
import React from 'react';
import Language from './Language'
import './App.css';

const Main = (props) => {
  //Datenarray Definition (MAP)
  let languageList = [
    {
      name: 'English',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
    introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
    },
    {
      name: 'Japanish',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
    introduction: 'Diese Sprache wird in Japan gesprochen.'
    },
    {
      name: 'Deutsch',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
    introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
    }
  ];

  return(
    <>
     <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
    </>
  )
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Function構文(Language.js)
import React from 'react';

const Language = (props) => {
// Übergeben "props" mit Daten als Argument
    return(
        <div className='language-item'>
        <div className="language-name">{props.name}</div>
        <img
        className='language-image'
        src={props.image}
        />
        <div className="language-introduction">{props.introduction}</div>
        </div>
    )
}

export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
function構文だと this がないのが特徴的です。

Github
こちらでは、アロー関数とアロー関数ではないのファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

以上が Class構文 と function構文 でした。
また下記は、function構文の注意点です。

function構文の注意! "state" が使えない

Reactでの制作経験があると、多くの場合は "state" 処理をしています。
しかし、タイトルにある様に "function構文" では state が使えません。なので、どうしても state を使いたい場合は "class構文" が書く必要があります。

しかし、先に述べた様に "function構文" を推奨しています。
では、 functionでstateを使用したい場合はどうすればいいのだろうか?
解決方法があります。それは "React hocks" を使用することです。

あとがき

ここまで読んでいただき、ありがとうございました。
学習をしていて、class構文やfunction構文で悩んでいたので、こちらを学習しました。
まだまだ、Reactについては浅学ですが、学習を続けたいと思います。

参考リンク

日本一わかりやすいReact入門#4 コンポーネント間でデータの受け渡しと再利用をしよう

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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

【React.js】class構文 と function構文

react-article-img.png

前書き

Reactを学習していた中で "class構文・function構文" を学習しましたので、こちらでアウトプットとして記録いたします。
学習されている方にお役に立てると非常に嬉しいです。

また、コードは Github で公開しているので気になるかたはダウンロードしてみてください。

class構文 と function構文とは

Reactをコーディングする方法として "class構文""fanction構文" があります。
これらの表記は↓になります。

Class構文
import React from 'react';

class 関数名 extends React.Component {
    render(){
        return(
         <React.Fragment>
          処理
         </React.Fragment>
        );
    }
}

export default 関数名;
function構文
import React from 'react';

function 関数名(引数) {
  return (
    <div className="Comment">
     処理
    </div>
  );
}

export default 関数名;

また、function構文にはもう1つ表記方法があります。

arrow関数
import React from 'react';

const 関数名 = (引数) => {

    return(
        <>
        処理
        </>
    )
}

export default 関数名;

こちらは、ES2015(ES6)アロー関数で表記されたものです。

どの構文で書けばいいのか?

業務環境により、構文使用の優先度は異なると思いますが、できるだけなら "function構文のアロー関数" で表記する方が良いです。

その理由は "class構文" よりも "function構文" の方が シンプル に表現できるため。
コーディングをする上では、複雑なコードを書くよりも、シンプルに表記される方が好ましいです。
また、Javascriptの使用は現在では "ES2015(ES6)" が推奨されます。アロー関数は ES2015 に該当するので使っていく方が良いでしょう。

しかし、アロー関数 は全てのブラウザで表示可能な訳ではありません。
現在では大抵のブラウザは対応しますが、古い環境下だと対応していないのでこれは知識に入れましょう。

(アロー関数の動作環境)
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/Arrow_functions

また、次からは MAP配列を使った "class構文" と "function構文" のページを比較します。

class構文で書く

react-img-1.png

ここでは、横並びのコンテンツを "class構文" で書いてみます。
次に、function構文で同じ者を作るので、比較をしてみましょう

Class構文(Language.js)
import React from 'react';

class Language extends React.Component {
    // Übergeben "props" mit Daten als Argument
    render(){
        return(
            <div className='language-item'>
                <div className="language-name">{this.props.name}</div>
                <img
                className='language-image'
                src={this.props.image}
                />
                <div className="language-introduction">{this.props.introduction}</div>
                </div>
        );
    }
}



export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
class構文だとこの処理に "this.props.image" など this を使うのが特徴的です。

Class構文(Language.js)
import React from 'react';
import Language from './Language'
import './App.css';

class Main extends React.Component{
  render(){
    //Datenarray Definition (MAP)
    const languageList = [
      {
        name: 'English',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
      introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
      },
      {
        name: 'Japanish',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
      introduction: 'Diese Sprache wird in Japan gesprochen.'
      },
      {
        name: 'Deutsch',
      image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
      introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
      }
    ];

    return(
      <div>
        <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
        </div>
    );
  }
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Class構文(index.js)
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import Header from './Header';
import Footer from './Footer';
import Main from './Main';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
   <Header />
   <Main />
   <Footer />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

(行っていること)
個別のコンポネートを index.js に記しています。

※こちらでは、cssや他コンポネートは記していません。下記のgithubでコーディングファイルを共有しているので、気になった方はダウンロードをして確認してみてください。

Github
こちらでは、class構文のファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

class構文では "this" や が特徴的です。

では、function構文(アロー関数)で書いてみます。

function構文(アロー関数)で書く

Function構文(Main.js)
import React from 'react';
import Language from './Language'
import './App.css';

const Main = (props) => {
  //Datenarray Definition (MAP)
  let languageList = [
    {
      name: 'English',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_england.png',
    introduction: 'Diese Sprache wird vom Vereinigten Königreich und den Vereinigten Staaten gesprochen.'
    },
    {
      name: 'Japanish',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_japan.png',
    introduction: 'Diese Sprache wird in Japan gesprochen.'
    },
    {
      name: 'Deutsch',
    image: 'http://hudehisa.sakura.ne.jp/gitgub_image/react_flag_germany.png',
    introduction: 'Diese Sprache wird in Deutschland und der Schweiz gesprochen.'
    }
  ];

  return(
    <>
     <h1>Welche Sprache sprichst du?</h1>
        <div className='language'>
          {/* Datenarray aufrufen */}
          {languageList.map((languageItem)=> {
            return(
              <Language
              name = {languageItem.name}
              image = {languageItem.image}
              introduction = {languageItem.introduction}
              />
            )
          })}
        </div>
    </>
  )
}

export default Main;

(行っていること)
MAP配列を定義し、(MAPの)データ配列を呼び出しています。
アロー関数を使って (languageItem) => {return ‥} の中です。

Function構文(Language.js)
import React from 'react';

const Language = (props) => {
// Übergeben "props" mit Daten als Argument
    return(
        <div className='language-item'>
        <div className="language-name">{props.name}</div>
        <img
        className='language-image'
        src={props.image}
        />
        <div className="language-introduction">{props.introduction}</div>
        </div>
    )
}

export default Language;

(行っていること)
データを持つpropsを引数に渡しています。
function構文だと this がないのが特徴的です。

Github
こちらでは、アロー関数とアロー関数ではないのファイルをダウンロードできます。
(Githubでは、CSS・HTMLなど他データも含まれます)

以上が Class構文 と function構文 でした。
また下記は、function構文の注意点です。

function構文の注意! "state" が使えない

Reactでの制作経験があると、多くの場合は "state" 処理をしています。
しかし、タイトルにある様に "function構文" では state が使えません。なので、どうしても state を使いたい場合は "class構文" が書く必要があります。

しかし、先に述べた様に "function構文" を推奨しています。
では、 functionでstateを使用したい場合はどうすればいいのだろうか?
解決方法があります。それは "React hocks" を使用することです。

あとがき

ここまで読んでいただき、ありがとうございました。
学習をしていて、class構文やfunction構文で悩んでいたので、こちらを学習しました。
まだまだ、Reactについては浅学ですが、学習を続けたいと思います。

参考リンク

日本一わかりやすいReact入門#4 コンポーネント間でデータの受け渡しと再利用をしよう

Myリンク

また、Twitter・Portfolio のリンクがありますので、気になった方は
ぜひ繋がってください。プログラミング学習を共有できるフレンドが出来るととても嬉しいです。

Twitter
Portfolio
Github

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