20190804のJavaScriptに関する記事は16件です。

React Component について(React基礎講座3)

はじめに

今回は、React Component について書きます。

シリーズ

本記事はReact基礎講座のための連載になっています。気になる方のために、前の章は以下です。

JSXで変数を展開させたい場合やアロー関数について(React基礎講座2) - Qiita

最初の記事は、以下です。

Reactを使ってJSXの内容をレンダリングする(create-react-app)(React基礎講座1) - Qiita

コンポーネントとは

コンポートの概念は、関数と似ています。つまり、inputがあって、なんらかの処理をした結果を、Outputするパーツや部品のことをコンポーネントと言います。そして、このコンポーネントを組み合わせて、より大きなアプリケーションを構築します。

シンタックス

まずは、通常の React Element を作成して、そして次に React Component を作成しましょう。

React Element

import React from "react";
import { render } from "react-dom";

const returnTxt = () => {
  return <p>sample txt</p>;
};

render(returnTxt(), document.getElementById("root"));

スクリーンショット 2019-08-04 22.46.40.png

では、これを React Component で書いてみましょう。

React Component

定義する際は、いくつかルールがあります。

  • const で宣言する場合や、renderの第1引数のJSXとして渡す際、文頭を大文字にします
  • renderの第1引数のJSXとして渡す際、タグで囲みます(閉じタグも書く) 例: <Tag />
import React from "react";
import { render } from "react-dom";

const ReturnTxt = () => {
  return <p>sample txt</p>;
};

render(<ReturnTxt />, document.getElementById("root"));

結果は同じになりますが、React Componentが作成されている点が異なります。

では、話を進めて、React Componentに何か値を渡してみましょう。

その場合は、renderの第1引数のJSXの中に key="value"的な感じでReact Componentに引数的な値を渡します。

index.js
import React from "react";
import { render } from "react-dom";

const ReturnTxt = props => {
  return <h1>{props.title}</h1>;
};

render(<ReturnTxt title="My Blog" />, document.getElementById("root"));

delicate-butterfly-nvry9_-_CodeSandbox.png

引数を複数渡すこともできます。

index.js
import React from "react";
import { render } from "react-dom";

const ReturnTxt = props => {
  return (
    <div>
      <h1>{props.title}</h1>
      <p>{props.body}</p>
    </div>
  );
};

render(
  <ReturnTxt title="My Blog" body="hello, world" />,
  document.getElementById("root")
);

React Componentの中でpropsをの中身をみてみましょう。

console.log(props)

コンソールには、以下のように出力されます。

Object {title: "My Blog", body: "hello, world"}
    title: "My Blog"
    body: "hello, world"

titlebodyに、値が代入されているとわかります。

propsとして、受け取る以外の受け取り方もあります。先にコードを書いてみます。

index.js
import React from "react";
import { render } from "react-dom";

const ReturnTxt = ({title, body}) => {
  return (
    <div>
      <h1>{title}</h1>
      <p>{body}</p>
    </div>
  );
};

render(
  <ReturnTxt title="My Blog" body="hello, world" />,
  document.getElementById("root")
);

何が違うかと言うと、アロー関数の引数を受け取る部分に、なみ括弧(ブレース){ }で受け取ることで、今回であれば titlebody という変数にオブジェクトされた中身を入れて、直接この変数名で展開することができます。

propsで書くより、上記のように何を受け取っているかわかるのがいいと思います。

参考

  • 改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで | 山田 祥寛
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最短でElectron入門

Electron用のプロジェクト作成から1画面(メインウィンドウ)表示までの内容です。
「とりあえず起動させるまで」が目的なので、中身は普通のJavascriptです。

準備

まずはプロジェクト用のフォルダを作ります。
シェルとかコマンドプロンプトとかで中に入って次のコマンドを叩きます。

npm init

色々聞かれますが、デフォルトでOKです。
するとpackage.jsonが作成されるので、中身を変更します。

こんな感じの行を消して

"test": "echo \"Error: no test specified\" && exit 1"

代わりにこれを付け加えます。

"start": "electron ."

これでコマンドラインで"npm start"って叩いたら起動します。
これで準備完了です。

開発

まずはメインとなるindex.jsを作成します。
この後もいくつかファイルを作りますが、今回は全のファイルを最初に作ったプロジェクト用フォルダ直下に作成します。

この時、npm initで作ったメインファイルの名前にする必要があります。(デフォルトがindex.js)
もし「俺、変えちゃったよ!でも、何にしたか忘れたよ!」って言う、うっかりさんはpackage.jsonの"main"の値を確認してね。

それではindex.jsの中身です。

index.js
// 必要な機能の追加
const electron = require('electron');
const url = require('url');
const path = require('path');
const {app, BrowserWindow} = electron;

// メインウィンドウの名前。後々使いまわすので、ここで初期化。
let wndMain;

// 処理本体
app.on('ready', function(){
  // インスタンス化
  wndMain = new BrowserWindow({});
  // 画面用のHTMLファイル読み込み
  wndMain.loadURL(url.format({
    pathname: path.join(__dirname, 'wndMain.html'),
    protocol: 'file',
    slashes: true
  })); 
})

こんな感じです。
1画面出すだけなのでコードも少ない上、JavaScript開発者なら大体雰囲気がつかめると思います。
で、次は画面です。wndMain.htmlって名前のファイルを作ります。
別にインスタンスと名前を合わせなくてもいいのですが、
pathname: path.join(__dirname, 'wndMain.html'),で指定しているのと合わせる必要はあります。

wndMain.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Main Window</title>
</head>
<body>
  <h1>Hello Work!</h1>
</body>
</html>

titleタグがウィンドウ名になります。
必要ならCSSも追加してください。
普通のWEBデザインと同様に、head内に

<link rel="stylesheet" type="text/css" href="style.css">

で追加できます。

はい。これで終了です。

起動

それじゃー起動してみましょう。
次のコマンドを叩きます。

npm start

するとこんな感じの画面が出てくるはずです。
ele.png
よく見るとメニューがついてます。(ヘッダー下の黒いところ)
これ、デフォルトで勝手に付いてくるやつです。

最初にも言いましたが、「とりあえず起動させるまで」が目的なので機能的な事などは別の機会に!

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

【JavaScript】nodebrew経由でNode.jsとnpmをアップデートする

以前にnodebrew経由でNode.jsをインストールしていたのですが、それをアップデートしました。

以下、昔書いた記事です。

nodebrewでNode.jsをインストールする。

Homebrew

最初にnodebrewを管理しているHomebrewをアップデートします。

$ brew update

Node.js

現在のバージョンを確認します。

$ nodebrew list
v10.1.0

current: v10.1.0

アップデートします。

$ nodebrew install-binary stable

再度確認すると、現在nodebrewで管理されているNode.jsのバージョンが増えました。

$ nodebrew list
v10.1.0
v12.7.0

current: v10.1.0

安定版を使います。

$ nodebrew use stable
use v12.7.0

バージョンの切り替えが確認できました。

$ node -v
v12.7.0

npm

現在のバージョンを確認します。

$ npm -v
5.6.0

アップデートします。

$ npm update -g npm

バージョンの切り替えが確認できました。

$ npm -v
6.10.2

参考記事

Node.jsのアップデートはこちらの記事を参考にしました。
nodebrewでNode.jsをアップデートする

こちらの記事で紹介されているNode.jsのバージョン管理ツールはnというツールです。
今回はnpmのアップデート部分のみ参考にさせていただきました。
Node.jsとnpmをアップデートする方法

各ツールの繋がりがとっても分かりやすく説明されています。
npm とか bower とか一体何なんだよ!Javascript 界隈の文脈を理解しよう

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

JSXで変数を展開させたい場合やアロー関数について(React基礎講座2)

はじめに

今回は、アロー関数について書きます。

シリーズ

本記事はReact基礎講座のための連載になっています。気になる方のために、前の章は以下です。

Reactを使ってJSXの内容をレンダリングする(create-react-app)(React基礎講座1) - Qiita

JSXの中で変数を使いたい場合

変数の中身を展開させたい場合、なみ括弧(ブレース){ }で囲うと展開されます。

const greeting = "Hello, React"; // 変数代入
const jsx = <h1>{greeting}</h1>; // 変数の中身を展開

JSXの中は1つのタグで囲う

なので、以下だとエラーになります。

const greeting = "Hello, React";
const introduction = "My Name is JS";
const jsx = <h1>{greeting}</h1><p>{introduction}</p>;

エラーメッセージは

Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

タグは複数ある場合は、それを囲むタグを用意せよと。では、divタグで囲って見ましょう。

index.js
import React from "react";
import { render } from "react-dom";

const greeting = "Hello, React";
const introduction = "My Name is JS";
const jsx = (
  <div>
    <h1>{greeting}</h1>
    <p>{introduction}</p>
  </div>
);

render(jsx, document.getElementById("root"));

これでエラーは出なくなりました。

JSXで関数を使いたい場合

展開の仕方は変数と同じです。今回は、JSに最初から定義されているDateクラスの関数を使ってみます。

import React from "react";
import { render } from "react-dom";

// 今日の日付で Date オブジェクトを作成
let now = new Date();

const greeting = "Hello, React";
const introduction = "My Name is JS";
const jsx = (
  <div>
    <h1>{greeting}</h1>
    <p>{introduction}</p>
    <p>This Year is {now.getFullYear()}</p>
  </div>
);

render(jsx, document.getElementById("root"));

スクリーンショット 2019-08-04 16.24.08.png

今年の年号が展開されましたね。なみ括弧(ブレース){ }で囲うと、変数だけでなく関数やオブジェクトも使えると言うことがわかりました。

アロー関数で定義した中身を表示させたい場合

文字列とセットで今日の年号を返すアロー関数を定義して見ました。

import React from "react";
import { render } from "react-dom";

// 文字列とセットで今日の年号を返すアロー関数
const returnThisYear = () => {
  // 今日の日付で Date オブジェクトを作成
  let now = new Date();
  return `This Year is ${now.getFullYear()}`
}

const greeting = "Hello, React";
const introduction = "My Name is JS";
const jsx = (
  <div>
    <h1>{greeting}</h1>
    <p>{introduction}</p>
    <p>{returnThisYear()}</p>
  </div>
);

render(jsx, document.getElementById("root"));

呼び出すときは、今回もブレースで囲みます。{returnThisYear()}

正しく呼び出されたと思います。

アロー関数とは

アロー関数は ES2015(ES6) 以降生まれた 関数を定義するためのシンタックスです。thisの挙動をコントロールしやすくなるなどの利点があり利用されています。

シンタックス

昔からある関数の定義と比較して見ましょう。両方とも、文字列を返すだけの単純な関数です。

// 昔の関数
const mukashi_func = function() {
  return "昔の関数"
}
console.log(mukashi_func);
// => function mukashi_func() {}
// =>   <constructor>: "Function"
// =>     name: "Function"

// アロー関数
const arrow_func = () => {
  return "アロー関数"
}
console.log(arrow_func);
// => function arrow_func() {}
// =>   <constructor>: "Function"
// =>     name: "Function"

アロー関数で引数を渡す場合

const arrow_func = (param) => {
  console.log(param)
}
arrow_func('test');

// => test 

引数が1つなら、かっこを省略できます。

const arrow_func = param => {
  console.log(param)
}
arrow_func('test');

// => test 

引数が2つの場合は () を省略できません。

const arrow_func = (param1, param2) => {
  console.log(param1, param2);
};
arrow_func('first', 'second' )

// => first second

1ライナーでの書き方

const arrow_func = () => {
  console.log("one line");
}

arrow_func();

// => one line

上記は、return するだけなので、以下のように1行で書くことができます。

const arrow_func = () => console.log("one line");
arrow_func();

// => one line

アロー関数の色々な書き方(省略形)を紹介しました。

React でアロー関数を使用する

引数を2つ渡して、アロー関数でもらった引数を整形して、render()中のJSXに返す処理を書きます。

import React from "react";
import { render } from "react-dom";

const arrow_func = (no, name) => {
  return `no is ${no}, name is ${name}`
}

render(arrow_func(1,'taro'), document.getElementById("root"));

スクリーンショット 2019-08-04 17.49.53.png

参考

  • 改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで | 山田 祥寛
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascript~ヘルスケアwebサービスを自分で作る医者の日記~

数字タッチゲーム16から

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

[HTML/CSS] ある要素をWindowに無理やり合わせつつ、拡大率に対応する

はじめに

「普段は画面の横幅いっぱいに表示されてほしいけど、ブラウザの拡大率を操作したら拡大はされてほしい」を出来るだけ簡単に(雑に)実現する(ブラウザ依存、PC以外の動作は見ていません)

背景

普通は、

  1. 要素のwidthを100%にする
  2. Viewportで調整する1

で、解決すると思いますが、
例えば、対象の要素を直接触れないとか、画面ないの一部の要素だけに適用したいとかで使えない想定。

方針

transformでどんなサイズでも合わせてしまえばいいじゃない

結果

CSSだけで実現できないかと思ったが、一旦、断念してJavascriptを利用。
(Javascriptを絡めてしまうと如何様にもやり方はあると思うが)

  • スクロールバーに対応してない
  • ほかのWidth:100%のものと横幅が合わなくなる

あたりは対応していない。
Windowにfitするように試してるのでCodePenだと確認し辛い。

See the Pen Element Window Fit Test by minilabo (@minilabo) on CodePen.

試したこと

CSSだけで実現

最初はCSSだけで実現できないかと試したが、scale + calcを上手く扱えず、時間がかかりそうだったので断念

example.css
/* 計算結果の単位のせいか適用されない */
.ng {
  transform: scale(calc(100vw/2))
}

/* これだと動く */
.ok {
  transform: scale(calc(100/2))
}

諦めてJavascript使って動的に適用する

Javascriptで大きさを合わせるだけだと拡大率などに関わらず、Windowに合うだけなので、そのあたりの情報を調査する。

  • 拡大しているかの判定
    innerWidthが表示領域、outerWidthがwindowの大きさを表すので、 ブラウザの機能で拡大するとinnerWidthが小さくなるので、outerWidthに比べてinnerWidthが小さい場合、拡大されている。2
main.js
// スクロールバーなどが含まれる為、このまま計算すると少しずれる(が、雑に丸める)
const zoom = Math.round(window.outerWidth / window.innerWidth);
  • transformでサイズを変更しても親の要素のサイズに反映されない
    element.getBoundingClientRect()で高さを取得して、親要素に適用(単純にelement.offsetHeightだと、transform前の大きさがとれる)
    この関数はとても便利だが、環境によってはダメかも?(参考: https://developer.mozilla.org/ja/docs/Web/API/Element/getBoundingClientRect)
main.js
// tramsformの適用後の高さを取得して、親要素に適用してスペースを確保(今回は高さのみ)
parent.style.height = element.getBoundingClientRect().height;

  1. Viewportで初期の拡大率を1以下にすると問題があるよという記事を見たので参考に > もう逃げない。HTMLのviewportをちゃんと理解する 

  2. スクロールバーなどが含まれる為、このまま計算すると少しずれる 

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

Nuxt+Typescript+Auth0で認証してみる

はじめに

「Auth0を使って認証機能を実装」

Nuxt+Javasrciptで動作する記事は見かけたのですが、Nuxt+Typescriptで動作する記事が見つからなかったので、記載してみました。

下記にソースを置いています。
https://github.com/ryuzo-nakata/nuxt-auth0

0.環境

下記のバージョンで動作しています。

$ npm -version
6.9.0

$ node -v
12.1.0

$ nvm --version
0.34.0

1.Nuxtを使えるようにする

1-1.初期化

nuxt-auth0というフォルダを作成して、npm installpackage.jsonを作成します。

$ mkdir nuxt-auth0
$ cd nuxt-auth0

$ npm init

1-2.npxインストール

npxをインストールされていない方は、下記のようにインストールしてください。

$ npm install -g npx

1-3.create-nuxt-app

Nuxt.js プロジェクトの雛形を作成します。

$ npx create-nuxt-app

自分の環境では、nuxtのバージョンが2.8.1になっていました。

2. Typescriptを使えるようにする

2-1. Typescriptをインストール

Typescriptに必要なものをインストールします。

$ npm install @nuxt/typescript ts-node vue-property-decorator

2-2. tsconfig.jsonの作成

nuxt-auth0/tsconfig.jsonを作成します。

nuxt-auth0/tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "lib": [
      "esnext",
      "esnext.asynciterable",
      "dom"
    ],
    "esModuleInterop": true,
    "experimentalDecorators": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": false,
    "allowSyntheticDefaultImports": true,
    "noImplicitAny": false,
    "noEmit": true,
    "baseUrl": ".",
    "resolveJsonModule": true,
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@nuxt/vue-app",
      "@types/node"
    ]
  }
}

2-3. nuxt.config.tsへ変更

nuxt.config.jsからnuxt.config.tsへ変更します。

中身は下記のように変更します。

nuxt-auth0/nuxt.config.ts
import NuxtConfiguration from '@nuxt/config'

const config: NuxtConfiguration = {
  // Type or Press `Ctrl + Space` for autocompletion
}

export default config

これでTypescriptが使えるようになりました。

3. Auth0を使えるようにする

3-1 Auth0のDomainとClient ID

Auth0(https://auth0.com/jp/)
サインアップし、Applicationsを選択すると、下記の図のように表示されます。

auth0.png

DomainとClient IDの値を、のちほど使います。

3-2 Auth0のCallback

次に、Callbackを下記のように設定します。

callback.png

3-3. Auth0をインストール。

nuxtへauthに必要なものをインストールします。

$ npm install @nuxtjs/axios @nuxtjs/auth

3-3. nuxt.config.tsにAuthの設定を追加する

nuxt-auth0/nuxt.config.tsに下記の設定を追加します。
auth0のdomainとclient_idは、上記の図の値をいれます。

nuxt-atuth0/nuxt.config.ts
  modules: [
    // Doc: https://axios.nuxtjs.org/usage
    '@nuxtjs/axios',
    '@nuxtjs/auth'
  ],
  auth: {
    strategies: {
      auth0: {
        domain: 'Your Domain',
        client_id: 'Your Client ID'
      }
    },
    redirect: {
      login: '/',  // 未ログイン時のリダイレクト先
      logout: '/',  // ログアウト後のリダイレクト先
      callback: '/callback',  // コールバック
      home: '/home',  // ログイン後のページ
    }
  },
  router: {
    middleware: 'auth'
  },

3-4. ページの作成

auth0の使い方を見たいだけなので、ログイン画面、ログイン後の画面、コールバックの画面を作成します。

ログイン画面

nuxt-atuth0/pages/index.vue
<template>
  <div>
    <h1>Login Page</h1>
    <button @click="authenticate">Login</button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component({})
export default class Index extends Vue {
  authenticate() {
    this.$auth.loginWith('auth0')
  }
}
</script>

ログイン後の画面

nuxt-atuth0/pages/home.vue
<template>
  <div>
    <h1>Login Success</h1>
    <p>User Name: {{this.$auth.$state.user.name}}</p>
    <button @click="logout">Logout</button>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
@Component({})
export default class Logout extends Vue {
  logout() {
    this.$auth.logout();
  }
}
</script>

コールバックの画面

nuxt-atuth0/pages/home.vue
<template>
  <h1>callback</h1>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
@Component({})
export default class CallBack extends Vue {}
</script>

3-5. 各ページ認証してるか確認する

nuxtのmiddlewareを実装します。
nuxt.config.tsのrouterで、authを読み込むように設定しています。

nuxt-atuth0/middleware/auth.ts
export default function ({ store, redirect }) {
  if (!store.state.auth.loggedIn) {
    redirect('/');
  }
}

3-6. storeにindex.tsファイルを追加する

storeにindex.tsファイルがないとエラーになるので、下記のようにファイルだけ追加しておきます。

nuxt-atuth0/store/index.ts

3-7. $authをプロパティに追加する

エディタ上で$authプロパティをうまく認識してくれず、エラーを表示してしまします。。。

このままでも動作はするのですが、なんでだろう?教えてすごい人。

ひとまず、エラーを出さないようにするために、下記のように$authプロパティを自分で設定して回避しました。

nuxt-atuth0/nuxt.config.ts
declare module 'vue/types/vue' {
  interface Vue {
    $auth: any
  }
}

4. 動作

ローカルホスト上で動作してみましょう。

npm run dev

http://localhost:3000/へアクセスすると、NuxtがTypescriptで動作しています。

ログイン画面

login.png

loginボタンを押すと、Auth画面へ遷移します。

Auth画面

auth.png

auth0を使って、Signup / Login できます。

ログイン後の画面

success.png

ログイン後に表示されます。

おわりに

Nuxt+Typescript+Auth0で認証できるようになりました。
nuxt.config.tsstrategiesを追加すれば、ソーシャルログインをいろいろ増やすことができるので、サービスによって追加してみましょう。

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

XHRでのcsvファイルの複数同時読み込み

仕事柄csvファイルを簡易DBとした読み込み処理をすることが多いのですが、複数のcsvファイルを読み込みたいときも多々あります。
すぐ忘れるので覚書として書いておきます。

XMLHttpRequestで複数ファイルを読み込み

const f = (function(){
    let xhr = new Array(), i;
    for(i = 0; i < 2; i++){
        (function(i){
            xhr[i] = new XMLHttpRequest();
            url = "test" + i + ".csv";
            xhr[i].onreadystatechange = function(){
                if (xhr[i].readyState === 4 && xhr[i].status === 200){
                    //処置内容
                }
            };
            xhr[i].open("GET", url);
            xhr[i].overrideMimeType("text/plain; charset=Shift_JIS");
            xhr[i].send();
        })(i);
    }
})();

オフィス内ではExcelが標準的に使われるのがほとんどで、csvファイルをExcel側で再読み込みすることも多々あります。
文字コードなんぞやという方が殆どですので、Excelに合わせて文字コードはcsvファイルはShift_JISのままの方が良いです。
コーディングは当然utf-8ですけど。
いい加減officeもutf-8が標準になってくれればもっとシームレスになるんですけども(´・ω・`)

あ、どうでもいいですが「"」「'」は「"」派です。
だってShiftから近いんですもの(´﹃`)

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

変数に入れてない整数を桁数表示する方法(JavaScript)

できない

3.toFixed(1); //Uncaught SyntaxError: Invalid or unexpected token

できる

3.0.toFixed(1); //3.0
(3).toFixed(1); //3.0

理由についてはわからないので聞かないで下さい
コメントいただきました。
前者の場合は3.の段階で小数点として解釈されてしまいエラーが起きるみたいです。

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

Reactを使ってJSXの内容をレンダリングする(create-react-app)(React基礎講座1)

はじめに

webページにレンダリングをする必要最小限の React App を実装するのに必要なことを書いていきます。

開発環境

  • codesandbox(POPULAR TEMPLATESはReactでCreateする)

不要なファイルは削除しています。

import について

import自体は、ES2015(ES6)から導入されたメソッドで、これを使うと、JSのパッケージ(モジュール)の中身(関数や変数やクラスなど)を使えるようになります。

なので、読み込めばこのファイルindex.jsで定義されていない関数や変数やクラスなどの、JSのモジュールをindex.jsで使えるようになります。

index.js
import React from "react";

これは、reactというパッケージ(モジュール)から、Reactimportしていると言うことになります。上記を追加することで、Reactを読み込んでrenderメソッドなどを使えるようにしています。

render() について

index.js
import { render } from "react-dom";

これは、react-domというパッケージ(モジュール)から、renderというページにレンダリングするメソッドをimportしていると言うことになります。

render() は2つの引数を必要とします。

render(JSX, target)
  • JSX: JSの拡張言語で、HTMLのようなもの
  • target: 作成したReactアプリを、どこのDOM Elementsに紐づけるかの指定

と言うことで、結果、以下のようになります。

render(<h1>Hello, React</h1>, document.getElementById('root'))

このよう書くと、React(のrennder)が、index.htmlにあるタグの中の<div id="root"></div>の中に、JSXで記入した内容をレンダリングします。

コード

index.js
import React from "react";
import { render } from "react-dom";

render(<h1>Hello, React</h1>, document.getElementById("root"));

結果

スクリーンショット 2019-08-04 00.06.07.png

JSX は HTML ではない

JSXですが、とてもHTMLに近いシンタックスですが、JSのファイルのなので、本来HTMLはかけないし、実際、HTMLではありません。
では、なぜwebページにHTMLぽく表示されるのかというと、babelなどの開発環境がJSXReact Element(JSのオブジェクト)にトランスパイルしてくれているからです。JSのオブジェクトなので、変数代入や、console.logでの表示など、JSの操作が可能になります。

JSのオブジェクトになった段階で、render()メソッドでレンダリングを可能にしています。

例えば、JSXを変数(jsx)に代入して、console.logさせることも可能です。

delicate-butterfly-nvry9_-_CodeSandbox.png

jsにおけるオブジェクトとは

詳細には記述しませんが、オブジェクトとは、名前をキーにした配列です。Rubyでいうハッシュです。連想配列と言ったりもするJSのデータ型の1つです。

参考

  • 改訂新版JavaScript本格入門 ~モダンスタイルによる基礎から現場での応用まで | 山田 祥寛
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptのPromiseをpythonで実装する方法

Motive

selenium でスマホ版でブラウザを起動しようと思った時、

    sp_args = "--user-agent="
    sp_args_list = ["Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X)",
                    "AppleWebKit/602.3.12 (KHTML, like Gecko)",
                    "Version/10.0 Mobile/14C92 Safari/602.1"]
    sp_args += " ".join(sp_args_list)

と設定するだけでは一部のサイトではレスポンシブになっているため対応しない場合があります。

そのため、 width を450くらいにしてリロードをするとスマホ版の表示になるのですが、ブラウザ設定 → スマホ画面の大きさを設定 -> リロード の順に一つのプロセスが完了したことがcompleteになった状態で次のプロセスに移す実装ができないかと思ったわけです。

で、 javascriptの非同期処理で使われるPromiseと同等のものがpythonでできないかと考えたわけっす。

Preparetion

pip で探すと早速パッケージが見つかりました。ふつーに

pip install Promise

で良いです。

Model

参考にしたサンプルコードですが初めてのJavaScript 第3版 ――ES2015以降の最新ウェブ開発 14章 非同期プログラミングにあったロケット発射モデルを題材にしました。

元コードからブラウザに表示する編集等々でちょっと変えています。

<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <script type="text/javascript" src="./sample.js"></script>
    </head>
    <body>
        <h3>apolonX</h3>
        <div class="box">
        </div>
    </body>

</html>

$(()=>{

    countdown(10)
    .then(()=>{
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                //大気圏突入
                resolve(insertBox("atmosphere..."));
            }, 2000);
        });
    })
    .then(()=>{
        //成功
        insertBox("success!!");
    });

});

//カウントダウン
function countdown(seconds){
    let dst = new Promise(
            (resolve, reject) => {
                for (let i=seconds;0 <=i;i--){
                    setTimeout(() => {
                        if(i>0){
                            insertBox(countSign(i));
                        } else {
                            resolve(insertBox(goSign()));
                        }
                    }, (seconds-i)*1000);
                }
            }
        );
    return dst
}


function insertBox(src){
    let p = $("<p>")
    p.text(src);
    $(".box").append(p);
}

function countSign(index){
    return index + "...";
}

function goSign(){
    return "GO!";
}

で約2秒ごとにブラウザにメッセージが表示されます。

count.gif

Method

from promise import Promise
import time

def main():
    countdown(10).then(go()).then(Promise.resolve(atmosphere())).then(success())

def countdown(seconds):
    def myfunc(resolve, reject):
        for i in reversed(range(0,seconds + 1)):
            if 0 < i:
                print( str(i) + "..." )
                time.sleep(2)
            else :
                resolve()
    return Promise(myfunc)

def go():
    time.sleep(1)
    print("GO")


def atmosphere():
    time.sleep(1)
    print("atmosphere")

def success():
    print("success!!")


if __name__ == '__main__':
    main()

countdown(10).then(go()).then(Promise.resolve(atmosphere())).then(success())
でチェイン化しています。

Aug 4 2019 1_22 PM - Edited.gif

Future

複数のAPIでデータ取得後に一括処理して文章生成するなどのケースであったら、全てのAPIのデータ取得後に一括処理する一貫性が保たれるので何かと良い。
簡易的なトランザクション処理ですかね。

Reference

promise
promise:github
初めてのJavaScript 第3版 ――ES2015以降の最新ウェブ開発 14章 非同期プログラミング
Python の Promise 実装とその活用方法について / How to implement Promise by Python and how to use it

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

RPGアツマールのグローバルシグナル

概要

RPGアツマールには非同期ネットゲームを想定したAPIが存在します
その中の「グローバルシグナル」を使ってみた記事です

以前、ユーザーシグナルについての記事を書いているので
基本的な解説は重複しているところがあります

作ったもの

  • レイドバトル(エンディング後の要素にしています)

作ったものの具体的な説明については別な記事で書こうと思います

シグナルとは

ユーザー間での情報のやり取りを、シグナルという機能によって行えます
シグナルには100byte以内の情報(文字列)を入れることができます

例えば、送り側で以下のようなjsonの文字列を作って送信します

{ SignalId:1, SaveIdx:1, Hp:10000 }

受け側ではシグナルを取得すると送られた上記の文字列を取得できます
jsonを解釈することで、送り側から送られたSignalIdとSaveIdxとHpの値が分かるという流れです

送り側のユーザーIDや名前はこれとは別に付与されているので含めなくて大丈夫です

シグナルには「ユーザーシグナル」と「グローバルシグナル」があります

ユーザーシグナル

指定したユーザー間で情報をやり取りするときはユーザーシグナルを使います
送り先のユーザーIDを引数に指定して目的のユーザーに送信します
使い方のイメージは以下の記事にまとめています

グローバルシグナル

全ユーザーに対して情報を送るときにはグローバルシグナルを使います
ユーザーシグナルとの違いは

  • 全ユーザーに対して送信する
  • 自分発信のシグナルを受信する

という辺りです

グローバルシグナルの動き

本記事ではグローバルシグナルを解説します
全ユーザーに対して送る「グローバルシグナル」の動きを解説します

送り側は
window.RPGAtsumaru.experimental.sendSignalToGlobal()
を実行します

1回送ると全ユーザーが取得できるようになります

送り側とたくさんの受け側(自分も含む)がいて

図1.png

1件送るとこうなって・・・

図1.png

また1件送るとこうなって・・・

図1.png

サーバーに蓄積されていくイメージです

受け側は
window.RPGAtsumaru.experimental.getGlobalSignals()
を実行します

各ユーザーごとに、
1回の実行で先程送られた2件を全部取得します

図1.png

またこの後に、送り側から3件目、4件目を送信してから、
受け側でシグナルの取得を行うと、受け側では1~4件目を全部取得してしまいます

APIの実行では全部取得してしまうので、
ゲーム側で新しいシグナルだけを読みたい場合は、
どこまで取得したかの情報をクライアントで持っておく必要があります

公式プラグインの AtsumaruGlobalSignalExperimental.js が、
この辺りの制御をうまくやっていて、全シグナルを取りつつ、
ゲーム側には新しいシグナルしか渡さないようになっています

シグナルの情報が移動するイメージはユーザーシグナルとほぼ同じですが、
送る時はユーザーIDを指定せずに全員が取得できるように送ります
全員が取得できるということは自分も取得できてしまいます

公式プラグインを読み解く

ユーザーシグナルのものとほぼ同じです
上記の解説記事をご参照ください

すべてのシグナルを取得できない可能性がある

こちらはユーザーシグナルもグローバルシグナルも同じですが
以下のことに注意してゲームの仕様を決める必要があります

  • 一定の件数/容量を超えると古いものから削除される仕様のためシグナルは全て受け取れない可能性がある
  • 件数や容量の詳細は公式の制限詳細を参照してください

特にグローバルシグナルの場合全ユーザーのシグナルが来るので
古いものが欠落する可能性が高くなると思います

自分発信のシグナルを受け取る

グローバルシグナルはユーザーシグナルと違って全員が取得できるシグナルのため、自分が発信したシグナルを自分が受け取ることになります

例えば「誰かがログインしました」的な通知はグローバルシグナルで実現できると思いますが、自分のログイン通知をゲーム画面に出さなくてもよい仕様なのであれば、自分発信のシグナルを受け取ったときに除外するようにします

シグナルには発信者のユーザーIDが付与されているので、それが自分のユーザーIDと一致したら処理しない、とすればよいです

まとめ

グローバルシグナルの仕組みの説明と、使うときの注意点をまとめてみました
公式プラグインを使うだけであってもどういう動き方をしているのかが分かれば使い方のイメージがしやすいかなと思います

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

イベントオブジェクトfunction(e)のeとthisの違いについて 簡易メモ

この記事について

jQueryの学習中に気になったことを調べ、解決したので
メモとして書いています。

・違いについて調べた経緯

ブラウザが元々持っている処理をキャンセルするメソッド
preventDefault()についての学習で以下の
コードが書かれていた。

script.js
$(function() {
  $('form').on('submit', function(e) {
    console.log('送信ボタンが押されました');
    e.preventDefault();
  });
});

このコードを見たときにeのイベントオブジェクトをfunctionの第一引数として持たせているが、thisでもいいのでは?
と思い,
イベントオブジェクトfunction(e)のeとthisの違いについて
調べました。

eとthisの違いについて

・this

関数の中に記述することでイベント発生元の要素を取得することができ、関数内で使用できる。上記のコードだと$('form')の要素。

script.js
$(function() {
  $('form').on('submit', function() {
    this == $('form')//←イメージ
  });
});

・イベントオブジェクトe

function(e)と記述することでイベント発生元の要素だけでなく押されたキーの情報なども取得できる。

script.js
$(function() {
  $('form').on('submit', function(e) {
    e == $('form').on('submit',//←イメージ
  });
});
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GASでSlackボット作成

Slack APIを使いこなす

Documents

postMessage

messageをSlackチャンネルにポストする関数

var postMessage    = "https://slack.com/api/chat.postMessage";
var app_auth_token = "xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var channel        = "#xxxxxxxx";
var message        = "It is sample message!!";

function postMessageToSlackChannel(app_auth_token, channel, message){

  const params = {
    "token" : app_auth_token,
    "channel" : channel,
    "text" : message
  };
  const payload = JSON.stringify(params);

  const options = {
    "method"      : "post",
    "contentType" : "application/json",
    "headers"     : {"Authorization" : "Bearer "+ app_auth_token},
    "payload"     : payload
  };

files.upload

fileをSlackチャンネルにポストする関数
postMessageと違ってoptionsの指定channelが複数形になっていないと指定されたチャンネルにアップロードされなくてつまづいた。
仕様書はよく読みましょうということ。

※今回はSpreadSheet上のファイルをアップロードする。

var postMessage    = "https://slack.com/api/files.upload";
var app_auth_token = "xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var channel        = "#xxxxxxxx";
var wsName = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート名");
var charts = wsName.getCharts();
var filename = 'chart.png'
var file = charts[0].getBlob().getAs('image/png').setName(filename);

function uploadFileToSlackChannel(app_auth_token, channel, file){

  const payload = {
    "token"          : app_auth_token,
    "channels"       : channel,
    "file"           : file
  };

  const options = {
    "method"      : "post",
    "payload"     : payload
  };

  return UrlFetchApp.fetch(uploadFileUrl, options);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Typescript(Javascript)でURLクエリパラメーターを更新する

URLクエリパラメーターを更新するクラス

※ Typescriptで書いてます。Javascriptの場合は型指定あたりを削除すれば動くと思います。

class MySearchParams {
    static update(key: string, value: string): boolean {
        const params = MySearchParams.toObject();
        params[key] = value;
        const url = "?" + Object.keys(params).map(
            (key: string) => key + "=" + params[key]).join("&");
        history.replaceState('', '', url);
        history.pushState('', '', url);

        return true;
    }

    static get(key: string): string {
        const params: any = MySearchParams.toObject();
        return params[key];
    }

    static toObject(): Object {
        let vars = {}, max: number, hash: any, array: any = "";
        let url = window.location.search;

        if (url.length === 0) {
            return vars;
        }
        hash = url.slice(1).split('&');
        max = hash.length;
        for (let i = 0; i < max; i++) {
            array = hash[i].split('=');
            vars[array[0]] = array[1];
        }

        return vars;
    }
}

使い方は以下のとおり

指定パラメーターの更新

MySearchParams.update(key, value)

全てのパラメーターを連想配列で取得

MySearchParams.toObject()

指定パラメーターの取得

MySearchParams.get(key)

ブラウザのバージョンなどによっては、動作しないかもです。問題点などありましたら、コメントなどで指摘していただけると助かります<m(_ _)m>

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

ドットインストールjavascript~ヘルスケアwebサービスを自分で作る医者の日記~

数字タッチゲーム8の途中から

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