KAEDE Hack blog

JavaScript 中心に ライブラリなどの使い方を解説する技術ブログ。

React Netlify 公開について

ReactをNetlifyでBuildに成功した

今までledgerのようにFWでツールを作成したり

moneylogのようにhtml js css + firestoreで公開できるツールを作成したり

html css + github pages で1ページのサイトを作ったことはあるが

buildをして,その中身をwebで公開したことはなかった.なのでチャレンジ.

crieit.net

このサイトの通りにReactで作成したものをNetlifyのなかでdeployしてみた...

これがねっとりファイの中...暖かい...

まずは作業directoryでnpx create-react-app btest

cd btest

でreactのdefaultぐるぐるを作って入る.

GUIで専用のGithub repoを作って(privでもいける)

community.netlify.com

git init

git remote add origin git@....

git push -u origin master

ほいでgithubにpush (通らなかったからpush -f)

そしてNetlifyで自動buildしてもらう設定を組む

f:id:kei_s_lifehack:20200430230754p:plain

npm run build, build先はbuild/

f:id:kei_s_lifehack:20200430230525p:plain

そしたら通った!!!!

f:id:kei_s_lifehack:20200430230633p:plain

こんな簡単だとは!!( しかし後にcli-toolの方が早いと判明 )

ちなみに博士にこれでfirestore使えば楽チンですねって言ったら

「俺ならfirebase hosting使いこなせてないから落としますね」

って言われた,そのとおりだ... だがこれでReactでjsxを活用して

作ったSPAを手軽に公開できる手段を得た.

一応,firebase HostingではなくNetlifyを使うメリットとしては

webのGUIgithub repo からdeployができて,second domein (hoge.netlify.app) の 設定や,bulid logが見れたりと最低限の操作がNon PGな環境でもできる点だろう.

またfirebase では作成できるprojectに限りがある問題もある

f:id:kei_s_lifehack:20200517020225p:plain

kei-s-lifehack.hatenablog.com

なお以前書いたこのgithub pagesでのdeployとの違いとしては

  • Github アカウントとPlatformのNetlifyを分けて,Netlifyだけ職場のメアドで作れる
  • 職場のサイトにする場合,私が退職しても私のGithubのソースから簡単にスイッチできる

  • Github Pagesではusernameがそのままurlになるが,NetlifyではGUIで簡単にsite name (url sub domain)を編集して即座に反映できる

  • 最悪HTML CSSだけ別ツールで生成して,それをdrag and dropで持ってこれる

上記のメリットがある

またcontentfulというCMSサービスを使うと動的に中身を動かせる,ブログのようなものが作れるらしい.

fromscratch-y.work

Netlify CMS (not tried)

jamstack.jp

Netlify CMSという動的に動かせるNetlifyの内部サービスがある

どうdata/Workdata.jsxを組み込むのかはわからない

React props or state

分割その二

props

    super(props);
    this.message = 'Hello from Note Component';
    this.noteContent = props.noteContent;
    this.noteId = props.noteId;

propsのdataをclass直下に渡すことができる,??

State

  constructor(props) {
    super(props);
      this.state = {
        notes: [
          {id:1, noteContent: "Note 1 here"},
          {id:2, noteContent: "Note 2 here"},
        ],
    }
  }

propsとしてthisに直接書く以外に,stateとしてclassのconstructor で定義し,setStateで更新,追加することができる

props

アロー関数でもpropsは気軽に書ける。

const post = (props) => {
    return (
        <div>
            <h1>{props.title}</h1>
        </div>
    )

しかしこれにはstateは入らない。

stateを宣言or使用するためにはclassを書く必要がある。

stateは変化した時に全体が再描画されるが, propsはされない。(ではなんのためにComponentWillMountがあるんだ?)

  addNote(note) {
    this.state.notes.push(note)
  }

そしてComponentWillMountで更新する方法があるが,それは現在は 非推奨なので,

hooks, useState, useEffectで更新することが推奨されている

React Component の実用

why

class Componentを使用したReactでの動的サイト製作の記事

wesのReact Firebase Note App Tutorialを参考にして作っている.

index

index.js

import App from './App';
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

基本的にはindex.htmlにlinkがあるindex.jsが起点になる

そのindex.jsでComponentの読み込み地点となる App Component(以下App)をimportし,get...Idでrenderする

App

App.jsが基本的にCotainerになる.
このApp.js自体もComponentであり,としてindexでimportされている. 今回のアプリでのデータnoteを描画する<Note/>
noteを追加するためのform, <NoteForm/>を読みこむ.

Componentはclassを使い,基本的にこのように書く

App.js

class App extends Component {
  render() {
    return (
      <div>
        <h1>React and Firebase To-Do List</h1>
        <Note />
      </div>
    );
  }
}

file nameと同じclass nameをとり,render() { return( ) }のナカに 一つのdivを作り,そのナカにhtmlを書く.

Appではこのように他のComponentを<Hoge/>と呼び出す

jsなので当然他のファイルから使うためには Note.jsxでexport default Noteをして

App.jsでもNote.jsxを使うために

import Note from './Note/Note';

でexportされたComponentをimportする必要がある


そして今回はCRUDのReadの役割を果たすリスト表示のNote.jsx

Note.jsx

import React, { Component } from 'react';

import './Note.css';
import PropTypes from 'prop-types';

でまずReact, Component, css, PropTypesをimportする.

prop-typesは型を判定してくれる.(後述)

class Note extends Component {
  constructor(props) {
    super(props);
    this.message = 'Hello from Note Component';
  }

ここではconstructorを書き,superをして, このComponentのなかにmessageを直接定義する.

  render(props) {
    return(
      <div>
        <h1>{this.message}</h1>
      </div>
    )
  }
}
export default Note;

本当はstateを使う.

今回はrenderにもpropを食わせてpropsの値を表示する.

そうするとlocalhost3kでNote.jsxのComponent fileに書かれた内容が App.jsで呼び出されてこうやって表示される

f:id:kei_s_lifehack:20200413192934p:plain

NoteForm.jsx

前回のはstateの中身を各自cssを当てて表示するだけなので, stateにGUIから入れるためのinputのを新たに作成する

Appのfooter will go here...をに交換, NoteForm.jsxを作る.
react, component, cssをimportし,constructorにemptyなstateを作り,
renderにinputとbtnを設ける.

NoteForm.jsx > render()

  render(){
    return(
      <div className = "formWrapper">
        <input 
          className="noteInput"
          placeholder = "Write a new note..."
        />
        <button className="noteButton">Add Note</button>
      </div>
    )
  }

そしてApp.jsで使えるようにNoteFormをexport default NoteForm;してimportする.

これでinputとaddが表示された

f:id:kei_s_lifehack:20200414082149p:plain

input内のvalueとread-only

NoteFormのinputのvalueを追加し,stateの中身を{}で埋め込む

        <input 
          className="noteInput"
          placeholder = "Write a new note..."
          value =  {this.state.newNoteContent}
        />

これでこのComponentのstateのnewNoteContentがinputに 最初の読み込みに表示される.

f:id:kei_s_lifehack:20200414085710p:plain

だがこのままだとRead-Only Propertyだと警告をされる

index.js:1 Warning: Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field.

なのでonChangeを書き込む必要がある.
valueと同じように{}bracketで埋め込み, 関数のtriggerにする.

onChange

constructorのbracketの閉じた後にhandle関数を仕込む.

  handleUserInput(e) {
    this.setState({
      newNoteContent  : e.target.value,
    })
  }

これをrenderのinputのなかにonChangeで

onChange = {this.handleUserInput}

と仕込むと,このinputの中が変更されるたびにhandleUserInputがその中の valueで起動する.

だがこのままではCannot read property 'setState' of undefinedなので
constructorの中にbindする.そうすると使える.

  constructor(props) {
    super(props);
    this.state = {
      newNoteContent: 'New Note Content',
    }
    this.handleUserInput = this.handleUserInput.bind(this);
  }

ここでhandleUserInputにconsole.logでthis.stateを吐かせると

f:id:kei_s_lifehack:20200415164306p:plain

変更されるたびに中身を吐き出してくれる.

これがstateと連携したonChangeのhandleだ

これでGUIでinputからstateを変更できるようになる.

次は同じようにして,btnにonClickを仕込む.


btnにonClickをつけwriteNoteのtriggerにする

btnも同じようにrenderのタグ内に仕込む

        <button 
          className="noteButton"
          onClick = {this.writeNote}
        >Add Note</button>

propsには{}を使い,関数名の後に()はつけない.

setState({})を使ってstateを操作する関数を追加する.

  writeNote(){
    this.setState({
      newNoteContent: '', // empty input box
    })
  }

constructorの後にwriteNoteのfuncを書く.
とりあえずnewNoteContentをemptyにする処理を入れておく

    this.writeNote = this.writeNote.bind(this);

そして先ほどと同じようにbind(this)する. すると押すとinputの中にvalueで紐づけられているnewNoteContentというstateが
空のstringになるwriteNoteが起動するbuttonが完成する.


考えたらこれは動作テストで入れてる処理ではなく,「DBへの追加処理が発生したら 入力欄を空にする」という当たり前に必要なMethodだった.これがないからFirebaseとjQで作った家計簿アプリは「btnを押した時に追加した手応えがなくて連続押して,二つ同じものが入ってしまう」ということが起こりがちだったんだな

(悪い例: https://moneylog-e7c4b.firebaseapp.com/ )


NoteFormとAppの連携

AppでAppのstateにpushするaddNote()を作成してNoteFormのwriteNoteで使用させる.

ここではNoteForm Componentに作成したwriteNoteのなかにaddNoteを使用し,
そのaddNoteはApp.jsに書く.NoteFormのstateではなく,Appのstateに入れるためだ.

  addNote(note) {
    this.state.notes.push(note)
  }

これでstateの中のnotesというarrayを引数でとったnoteに追加する.

    this.addNote = this.addNote.bind(this);

handleやwriteの関数と同じように,Appのconstuctorのナカでbindする.

また,これだけではNoteFormで使えないので,
renderにある

          <NoteForm addNote={this.addNote}/>

という形addNoteの関数をNoteFormに渡す.

NoteForm use addNote

そしてNoteFormで使う.

  writeNote(){
    this.props.addNote(this.state.newNoteContent);
    this.setState({
      newNoteContent: '', // empty input box
    })
  }

Appのrenderの中で渡されたthis.addNoteはthis.propsの中にはいるので取り出し
ここNoteFormのstateの中にあるnewNoteContentをaddNoteを使って
Appのstateのnotesにpushする.

これでaddNoteにconsole.logを仕込んで見るとnotesは一つ増えているのが見える

0: {id: 1, noteContent: "Note 1 here"}
1: {id: 2, noteContent: "Note 2 here"}
2: "New Note Content"
length: 3
__proto__: Array(0)

だが画面の更新はされない.

previous noteを挟む

ここでaddNoteの処理に一つ噛ませる

  addNote(note) {
    const previousNotes = this.state.notes;
    previousNotes.push({
      id: previousNotes.length + 1,
      noteContent: note,
    });

    this.setState({
      notes: previousNotes,
    })
    console.log(this.state.notes);
  }

previousNotesという変数にstateのnotesを入れてから
その変数に引数でとった追加する内容であるnoteを
noteContentとして, さらに現在の追加さき配列notesの次の添字をidとして
pushする. 最後にnotesにpreviousNotesの内容を入れる. stateに直接値を入れては行けないからsetState({})を使用する.    回りくどく見えるが,stateを更新する処理を別の処理と分割するためにpreviousNote介する.長くなってきた時にわかる.

さらにreact特有のkeyを渡す必要が出てくる.これがないとエラー.

render, give state id, content, key,

だからApp.jsのrenderでnotesをmapで展開して,Note Componentにkey, id, Contentを渡すことで描画している.

これでlocalなReactのstateにinputを介して追加して,それを即座に更新して 表示することができるようになった.

conclude

おさらいすると,<App /> のstateにidとcontentのobjをもつ配列notesを作成.
renderではそのstateにあるnotesをmapで展開し,id, key = id, contentを
<Note />に渡す.<Note />ではconstructorでpropsから受け取り,
renderでcontentを表示する.そこにcssがかかってカードになる.また
propTypesによって型がstringかチェックが入る.

追加, ADD編ではaddNoteという関数をAppのconstructorの後に作り,
stateのnotesに配列の長さ+1でid,引数をcontentにpushする.
それを変数を介してsetStateし,この関数addNote()を<NoteForm />に私,
propから受け取り,inputのvalueにstate newNoteContentを組み込み,
onChangeでhandleしてe.target.valueからnewNoteContentに渡し,
btnのonClickで先ほど<App />からもらったaddNoteをpropから使って
addNoteにnewNoteContentを渡し,今inputのvalue に入っている
newNoteContentを空にする.

ReactはここでRenderが更新される.

これでCRUDのRead, Create, Updateの処理までができた.

これではbrowserをrefleshした時にstateに入れたdataも消えてしまうから,Firebaseに保存し,起動した時にFirebaseから値を取ってくる物にする.

その後,moneylogのようにhttpsでアクセスできるようにfirebase hostingを活用する.

React + Firebase app duplicate error

background

www.youtube.com

github.com

3years agoの wesのrepositoryと解説を頼ってfirebase + Reactのcrudを作ろうとした.

jQで掲示板もどきを作った時とは違うfirebaseの使い方,config fileを噛ませる
やり方になっている.

Frond End のReactのstateのところではうまくいったが,Firebaseとの接続で
この動画のとうりにやると,

Uncaught FirebaseError: Firebase: Firebase App named '[DEFAULT]' already exists (app/duplicate-app).

のErrorが出てしまった.

cause

nextで上がっているこのissueは関係なかった.

github.com

2018年のこの記事のコードと差分をとって原因が判明した.

qiita.com

原因は App.jsのナカでfirebase.initializeApp(config);をしていたのと
firebaseのdatabaseを使っていたことだろう.

2020現行verではApp本体でinitするのはダメになっているようだ.
またfirebaseにdatabaseが無くなって,firestoreになっている.

なのでwesの該当コードを次のように書き直した.

code (in src/)

Config/config.js (BEFORE)

export const DB_CONFIG = {
  apiKey: "-hoge",
  authDomain: "hogehoge.firebaseapp.com",
.........
};

最初はfirebaseのget web appからとってきた値を変数に入れてexportするだけで
initはApp側でやらせていた.これを

Config/config.js (AFTER)

import firebase from 'firebase/app';
import 'firebase/firestore';

const config = {
  apiKey: "-hoge",
  authDomain: "hogehoge.firebaseapp.com",
.........
};
const firebaseApp = firebase.initializeApp(config);
export const firestore = firebaseApp.firestore();

firebase, firestoreをconfig内でimportしてきて,
configでinitしたものにfirestoreも噛ませてexportする.

App.js (BEFORE)

import { DB_CONFIG } from './Config/config';
import firebase from 'firebase/app';
import 'firebase/database';

class App extends Component {

  constructor(props){
    super(props);
    this.app = firebase.initializeApp(DB_CONFIG);
    this.database = this.app.database().ref().child('notes');
.................

従来はconfig のkeyとかをそのまま変数に入れてexportしてきたものを
DB_CONFIGとしてimportしてこちらでinitしていたが,それではエラーが出るので
config.js側でinitをするようにした.

またどうもfirebaseのversionが変わってdatabaseがfirestoreという名称に
なったようなので,databaseを使うのをやめた.

AFTER

import { firestore } from './Config/config';
import firebase from 'firebase/app';
import 'firebase/firestore';

class App extends Component {
  constructor(props) {
    super(props);
    this.app = firebase.app();
    this.db = firebase.firestore();
    console.log(this.db);

firestoreという名前にしてinitが住んでfirestoreもかまされたものをconfigからimport
firebase/databaseをやめてfirebase/firestoreを持ってきた

これでconsole.logすると

t {GT: FirebaseAppImpl, zT: t, INTERNAL: {…}, KT: t, XT: "[DEFAULT]", …}
hm: (...)
app: FirebaseAppImpl
GT: FirebaseAppImpl {firebase_: {…}, isDeleted_: false, name_: "[DEFAULT]", automaticDataCollectionEnabled_: false, options_: {…}, …}
zT: t {Qr: Promise, Wr: false, jr: Array(0), Kr: null, Gr: false, …}
INTERNAL: {delete: ƒ}
KT: t {projectId: "note-app0902", database: "(default)"}
XT: "[DEFAULT]"
ZT: t {currentUser: t, I: true, R: 1, u: null, m: ƒ, …}
tm: n {}
em: t {host: "firestore.googleapis.com", ssl: true, credentials: undefined, timestampsInSnapshots: true, cacheSizeBytes: 41943040, …}
sm: t {serializer: t, Pa: ƒ}
__proto__: Object

が入っているので,これで接続が直せた!!

firestoreとdatabase

そもそもBack Endをfirebaseでやると一括りに説明されがちだが,

firebaseにはDBのfirestore, databaseがあり,さらにimgのstorageがある.

techblog.kayac.com

//カヤックさん丁寧な解説すごいな,エントリーしようかな

f:id:kei_s_lifehack:20200420202348p:plain

説明ではweb GUIでfirebaseのサイトのdatabaseタブからdatabaseが作成されていたが,現在はdatabaseタブを開くと大きくfirestoreが表示される.

私はfirestoreを作りながらdatabaseを呼び出していたらしい.

まぁfirestoreとか使う前にconfigでinitする段階でエラー出ていたから今回のエラーの 解決には関係ないけどね..onとか.pushとかdatabaseで使えていたメソッドがfirestoreで使えないのには注意が必要だ.

firebase全く簡単じゃないな....

Choose a Database: Cloud Firestore or Realtime Database  |  Firebase

システム, コンポーネント設計について

sytem component architecture

component arch, コンポーネント設計

why

qiita.com

やめたろう さんの記事を読んだ

<v-btn
  rounded
  depressed
  min-width="120"
  large
  outlined
  @click="cancel"
>
  キャンセル
</v-btn>
<v-btn
  rounded
  depressed
  min-width="120"
  large
  color="primary"
  @click="ok"
>
  OK
</v-btn>

このOK buttonとCancel buttonを各自component化しないと

複数ページ帰るときにぐちゃぐちゃになるというエピソード.

<CancelButton @click="cancel" />
<OkButton @click="ok" />

こうして使えばroundedを消すときに一斉痴漢より

遥かに安全に置換ができる

また,全てのページで使っているならば

/components/Heading2.vue
<template>
  <h2 class="heading2">
    <slot />
  </h2>
</template>

のようなとても小さいtag群すらもcomponentを作るメリットが

十分にある.

conclude

まとめると,徹底的にcomponentにしていくことで,仕様変更に非常に強く,

壊れる可能性が低いメンテナンス性の高いサイトが作れるということだった.

これだけだとどの設計書にも書いてありそうだが,非常にシンプルで具体的で

尚且つジョークも豊富でストンと理解できた.

qiita.com

彼の記事は非常にわかりやすい.

system-design-primer

https://github.com/donnemartin/system-design-primer/blob/master/README-ja.md

これを読んでまとめる

Twitterで流れてた

https://github.com/donnemartin/system-design-primer/blob/master/README-ja.md

Bought Udemy React Course

background

今まではYoutube Premireに1.4k / M 課金していることもあり
前述の記事のようなReact Tutorialをやっていた.
しかしながら先日ふとUdemyで1.4kのコースを購入し,
やっているときにこんなツイートを目にした.

This Tweet is unavailable.

....消すほどか??まぁ,有料のリソースの方が時間効率がいいという容姿だ.

そこで実際にYoutubeの無料教材とUdemyの有料教材の違いを意識してみると,
思った以上に質が違った.もちろんYoutubeのCrash Courceも非常に丁寧だが,

Udemyでは:
* 解説で喋ってる人が背景を切り抜いてジェスチャーだけが伝わるようになっている * 音質がとにかく良い, * 短く分割して何をやっているのか明確になっている

などが上質で時間効率の良さを感じた.適宜追加していこうと思う. 2020.04.16では04までしか進んでないしね.

https://www.udemy.com/share/101WbyAEIZdldTTXoF/

props.childrenでは中身はでない?

基本はstateの配列をthis.state.hoge[0].age の形で展開 若しくはmapで展開。

renderにonclickを仕込んでhandlerを設定。

stateの値を直接書き換えては行けない temp変数に入れる処理を書いた後に setStateを使ってその変数をstateに入れる。

だけどこれでhandler作るだけだとreloadが必要だから Component Mount系が必要なのかなー?

hooks, useState

useStateをimportして、 これを使ってstateを初期化する。 AppでComponent/ costructorの代わりに

let Person = props => { 
useState({
Persons : [


]
})
}

とある大阪の人事さんの友人に面接をみてもらった!

  ## 経緯 フォロワーの関西のSES会社の人事の方と話す機会があって,なんでも相談乗ってやーって言ってくれていたので,第一志望のソ●トブレーンに落ち,9社落選が積み重なっている今,喋り方に問題があるのか不満になって時間とってskypeで見ていただいた

事故紹介

なぜなりたいか,何がしたいかを説明した

Feed Back

  • 話が長い.結論を企業は求めている.前提が長い.君の話はそれを意識すれば1/3で済む
  • 企業が知りたいのは結果であり,それに対する肉付けを意識しろ

updated

  • 新しいやり方が好き,できることが増え,楽しいのがソフトウェアエンジニア.
  • どの端末でも作業できてwebで完結するシステムなら(順番待ちや手作業の時間ロス,嵩張る紙の場所ロス,目視手計算 書き写しミス,)でのロスが減らせると思った
  • -> だから簡単に誰でも使えて安価な作業ツールが作りたい

長所

よくある質問を実際にしてもらった.実際に手を動かしてものを作れるって言った

Feedback

  • 話すときに主語の回数が多い,自分が,自分が,自分が...って言ってるのを 自分でこれを作ることを企画して,設計して,改善して,作り直して...って言った方がいい 必死になってる(素人)感が伝わってしまう
  • だが逆にその下手さを逆手にとって,言葉が下手で,自己分析しすぎてしまうとか 笑いに変える?といいかも

    updated

  • 設計と計画と改善を自分で行ってcakeのs

短所

これ言ったら受からなそうだから言わなかった「入力ミスが多い」を言ってみた

Feedback

  • プログラミングでのエラー出て直す経験を通して改善されてることをいうべき
  • 単調な作業 => 改善するためのツールが思いつくなどで切り返す

やりたいこと

前線で開発がやりたいといった

Feedback

  • コード書きたいばかりは良くない
  • 下積みからできないやつだと思われてしまう.テスターやる
  • ただ内定は企業は取り消せないから,契約書類をちゃんと見て,別の部署だったら 何年で戻れると明記しろと言うべき.

Feedbackまとめ

とにかく不利なことを言うときは切り返すのが大事.前述のように. あとスキルを聞かれた時に「できると言ったら嘘になる.だがこれから学んでいっている (入社後?)できるようにしろと言われたらする」など

エージェントに関して

むやみにエージェントを使っているのが勿体無い.

採用時に会社からエージェントに年収の1/3(1M)が支払われる契約はGreenなど媒体に1 week 500kで出して.4人採用するのと比べてコスパが悪い

エージェントを使っている学生を忌避するが,広告のためにエージェントに登録している企業も多い.いきなりやめろとは言わないが,自分でも申し込む方が良い.エージェントが持っている企業には限りがある.学生を金としてみている傾向が強い.モダンなベンチャーは使っていない企業が多い.ソ●トブレーンの規模では同じあれがある可能性が高い

ソ●トブレーン ハラスメント疑惑

職業選択の自由があるんだから,(最終選考前に)うちに受かったら他の選考をキャンセルして欲しいといったのは違法.そこまでの強権を人事が振るうところだと,配属先なども人事の力が強すぎて一切希望が通らないかもしれない.

面接面談含めて7回あったのは全て面接と取っていい. だがその中で人事がプライバシーに突っ込んで上から目線で逃げ場のない意見の押し付けをする行為もハラスメント.( 学生が質問を無視できない人事の立場を利用して、ズイズイひとのプライバシーに踏み込んできた挙句に、あたしは佐藤さんの意見こうだと思うんですよ!そうですよね!だからうちに向いてると思うし前回の選考受かったんですよね!と否定したらうちに向いてないことだぞと暗に示すような「質問」)

でかい老舗自社開発は部門が多いから開発以外に回されやすい.

普通面接はいい印象で終わるべきなのに他社の選考キャンセルとプライバシーハラスメントをぶち込んでくるのはやばい

やはりでかい企業はどうしても立場が強くなって,大企業病?のパワハラ横行?圧迫面接などが起きがちだから逆にエージェントに1M払えないような小さい受託がおすすめ.

その他媒体などを教えてもらった!!

長く丁寧にほんと助かりました!!!