KAEDE Hack blog

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

作りながら学ぶReact入門 をやる

作りながら学ぶReact入門

買った本で体系的に一通りやろうとおもう

Reactとは

History

1995にjsが登場

2005にGoogle Map, GmailAjaxが注目を浴びる

jQueryなどの有用なlibraryが現れる

2010sにAngularJSなどと共にReact登場(2013)

FBそのものの巨大サービスのメンテナンス性を高めるために開発されたFW

従来のjs libとは違ってデータの変更で自動的に全画面表示処理が必要な場所?? を更新する

jQの必要な部分を更新する処理をなくしているのがポイントらしい.

ReactはVirtual DOMが必要最小限必要な箇所を自動で置き換えてくれる

component

header, menu, itemsList, shoppingCart,

などを論理的な部分にReactでは分割できる. それによりメンテナンス性の高いシステムが作成できる.

SPA

従来の開発( PHP? )は画面の更新がserver, clientで別れていたので

コードが複雑だったが,Reactは画面の作成をclientのjsが担当するので

わかりやすいフロントとバックの分担ができるようになったらしい.

server側の処理が従来と違ってSmartPhoneでも同じにできるらしい.

画像を見ると,MVCのController, ModelをServer, Clientの両方で行い

相互のControllerでjsonをやり取りするらしいが,意味不明.

ENV, 環境構築

mkdir making-learn-react

cd making-learn-react

npm init -y

RYOs-MBP:making-learn-react kaede$ npm init -y
Wrote to /Users/kaede/code/making-learn-react/package.json:

{
  "name": "making-learn-react",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

これでシンプルなpackage.jsonを生成できる

これを

+   "description": "Hello React",
+   "private": true,
+   "scripts": {
+    "start": "webpack-dev-server",
+    "webpack": "webpack-d",
+   },

に書き換える( + はわかりやすくするため)

説明をつけて,private projectに設定して, webpack-dev-serverでlocalhostでserveできるようにして, webpack-dで何かをする???

そして忘れずにgithubにpush.

github.com/new

からmaking-learn-reactで作成し

git init

これでlocalに残ってるgitのデータをリフレッシュ

git remote add origin git@....

現在地がリンクするremote(github)の接続情報をつける

git add . git commit git push origin master

いつもの追加コマンド

To github.com:kaede0902/making-learn-react.git

  • [new branch] master -> master

これでリンクできた.

...

面倒だが書いてあるとうりにconfig fileを babelrc, eslintrc, webpack.config.js,

を書き写し,npm start すると

err 1

webpack-cliがseparate されたエラーが出た npm i -D webpack-cli

これで起動すると babel loader のエラー?

f:id:kei_s_lifehack:20200402082841p:plain

babel-loaderにはbabel-coreが必要で,それが含まれるbabel@7.x系をinstall

白と出る.

npm uninstallして@7をinstallした

err 2

今度はeslintが読まれない

f:id:kei_s_lifehack:20200402083605p:plain

各ファイルでこれが現れている. eslintはnpm --saveで入れた

react_devtools_backend.js:6 ./node_modules/scheduler/index.js
Module Warning (from ./node_modules/eslint-loader/dist/cjs.js):
Failed to load config "eslint:recommend" to extend from.
Referenced from: /Users/kaede/code/mkreact/.eslintrc.json

morizyun.github.io

eslintはes6のミスを指摘してくれるツールらしい?なら入れないといかんな

terminalに出てくる ( i ) 「wdm」ってなんだ?

terminalに全角文字とか出さないで欲しいんだが?

eslintシリーズをpack.jsonから消して,package-lock.jsonも消して,node-modules/を削除して,npm iで他のものを入れ直した

@6.8.0が入った

eslint, eslint-loader, eslint-plugin-react,

質問を投げました

teratail.com

.eslintrc.json

"extends":[ "eslint:recommend", "plugin:react/recommended"],

はい,typoだった

err 03

webpack rcのstyle-loaderをlodaerにtypoしてなかなか気づけなかった

f:id:kei_s_lifehack:20200403211752p:plain

webpack

webpackはその名の通りにcss, js, img, を一つにまとめているらしい.

webpackとはCSSJavaScript、画像などWebサイトを構成するあらゆるファイルを1つにまとめるモジュールバンドラーのことです。

www.mitsue.co.jp

出力先のjsに全てがまとまっている?

f:id:kei_s_lifehack:20200403220106p:plain (img in qiita)

qiita.com

またentry pointでapp.jsでindex.jsを読み込み,npm startでwebpack dev serverを動かせてくれる.これを使う方がerrの表示がていねい?

また,処理時間,パフォーマンスを教えてくれる?

npm serverの他に-dで何かができる

jsx

実際にhtmlを書いてみるとthreadの鑑賞で崩れが起きたから抜いた!!

threadはもちろんtbodyもいらん

table, tr, th, /th, /tr, tr, td, /td, /tr, /table,

で十分だ!!!

forEachでjsxを簡略化する作戦は失敗

          {books.forEach(hoge => {
            console.log(hoge.date);
            return(`
            <tr>
              <td>${hoge.date}</td>
              <td>${hoge.item}</td>
              <td>${hoge.amount}</td>
              <td></td>
            </tr>
            `)
          })}

これだとうまく帰ってこない

かといって本の通りに

          <tr>
            <td>{books[1].date}</td>
            <td>{books[1].item}</td>
            <td></td>
            <td>{-books[1].amount}</td>
          </tr>

を四回書くのはいやだ.

どうしようか....

React + Firebase Note App Tutorial(Wes's) dev log

Did React + Firebase Note App Tutorial

why

jQとFirebaseで家計簿アプリ作ってたらG-stylussの逆求人もくもくのイベントで
話した学生全員にReact使って書けって言われた

cakeのledgerで改善点探してたらだいたいUIだったからメンテしやすいらしいReactというFront End Frame workを試してみる.

ledgerはdeployできてないので,簡単にできると聞いたfirebaseと相性良さそうなreactを選択,

とりあえずはYoutube Premirem契約してるし,この動画の通りにやって,自分の言葉で解説をかく学習方法を取ってみる.

しかし現在は推奨されていないRDBを使っていたので,Firestoreで置き換えて使用しようと思う

f:id:kei_s_lifehack:20200414071901p:plain

教材としてはYoutubeでwesのTutorialをベースとして使ったが
databaseからfirestoreに変えるためにDjamWareを参考にした.

www.youtube.com

環境構築

まずはnpmで汎用ツールをぶち込む

npm i -g create-react-app
create-react-app reactnotes

結構時間がかかる

cd reactnotes
npm start

でテスト,browserで動けばOK

あとnpm -i --save firebaseでbackendのfirebase 入れる

f:id:kei_s_lifehack:20200410150928p:plain

作成されたここのsrc/にYoutubeの通りにjsxを書いていく.

github.com

code

Component

React Component の記事に移設

, , , に分割して, AppでNoteとNoteFormを呼び出し,indexで総括する.


props

Noteのconstructorに直接propsとして値を埋め込む方法がある.

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

super(props)の下にnoteContent, noteIdを定義してpropsの下から this(このclass?)のに付け足す.

CSS, className
  render(props) {
    return(
      <div className = 'note fade-in'>
        <p className="noteContent">
          {this.noteContent}
        </p>  
      </div>
    )
  }

ReactではhtmlのclassはclassNameと書く必要がある.

render配下にさっき作ったthis.noteContentをうめ込む. これでNote Componentの中のnoteContentがrenderされる

propTypes

importしてあるProp Typesで型のチェックができる

Note.propTypes = {
  noteContent: PropTypes.string
}

これで中身がstringでなければ警告が出る
参考
qiita.com

propsはコンポーネント作成時に値を指定することでコンポーネントで表示させたいデータを指定できます。 React.jsでコンポーネントを定義する時に、PropTypesを指定することでpropsにおける引数の入力チェックを行えます。 数値や文字列、配列などのバリデーションを行いたい時に便利です。

add App.css, No Static img,

github.com

ここのCSSをpaste.

使用する'./Static/img/2.jpeg'をpaste....
なかったの

代わりにpexelsのこれを使わせてもらいStatic/img/作ってぶち込んだ

https://www.pexels.com/photo/when-will-you-return-signage-1749057/

すると見栄えがよくなった

f:id:kei_s_lifehack:20200414070810p:plain

add Google Font

Parmanent Markerを選択 f:id:kei_s_lifehack:20200414071106p:plain

Latoも選択してimportのlinkをもらう f:id:kei_s_lifehack:20200414071342p:plain

そして,index.cssを全て消してこのimportだけに書き換える! これで筆っぽいheadingは表示される.

add Note.css

お次はNote.cssをpaste....

完璧に組まれた!!!

f:id:kei_s_lifehack:20200414071901p:plain

次にFirebaseの処理に移る.

Back End

config.js

Firebaseを使う.configはsrc/Config/config.jsに記述.
ここにFirebase Console のsettingからadd web app, Configでcopyする

f:id:kei_s_lifehack:20200418202100p:plain

これを先ほど作ったconfig.jsにpasteして,

const firebaseConfig = {
  apiKey: "hoge";
......
};

のconst firebaseCofig = をexport const DB_CONFIG =に書き換える
これでimportしたDB_CONFIGをAppで

import { DB_CONFIG } from './Config/config';

して使用する.

firebase/app

import firebase from 'firebase/app';

そしてfirebaseもimportするが,これだけでは

index.js:1 ./src/App.js
Module not found: Can't resolve 'firebase/app' in '/Users/kaede/code/note-app/reactnotes/src'

のerrが出てしまう.

Youtuberのgithubのpackage.jsonとくらべたらfirebaseをnpm i --saveしてなかった!

したら

Line 5:10:  'DB_CONFIG' is defined but never used  no-unused-vars
Line 6:8:   'firebase' is defined but never used   no-unused-vars

の「DBもfirebaseのAPI?も使われてないよ〜」のwarnしか出なくなった!!

Appのconstructorのナカに

    this.app = firebase.initializeApp(DB_CONFIG);
    this.db = this.app.database().ref().child('notes');

DB_CONFIGの内容でappをinitして,そこからDBのnotesテーブルを読みこむ.

component mount

ここが一番わからない

  componentWillMount() {
    const previousNotes = this.state.notes;
  }

componentWillMountのナカにaddNoteに入れていたprev notesを入れる

    this.database.on('child_added', snap => {
      previousNotes.push({
        id: snap.key,
        noteContent: snap.val().noteContent,
      });
      this.setState({
        notes: previousNotes,
      })
    })

さらにdbに子供が追加された時に,一時変数snapをとって
event drivenで関数を実行する処理を書く.
idには引数snapのkey, contentには引数の中身のnoteContentを
jQでよく使うvalを使って入れて,prevNotesにpushする.

そしてprevNotesをstateのnotesに組み込む.

変数prevNotesを噛ませるのは最初は冗長に見えたが,こうして処理が複雑に
なってくるとstateへ渡す処理をこうして分離するのは合理的に見えてくる.

duplicate err

なおこの段階でimport firebaseをした時に,

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

とimportがduplicateしてる?エラーが出る

kei-s-lifehack.hatenablog.com

別の記事にまとめた.configl fileのやり方が変わっていたらしい.

その上でjQのアプリの時のようにfirestoreの解決策を取ろう.

add note

さっきのcomponentWillMountの処理で既存のaddNoteの処理は空になったので
そこに書き足していく.

databaseがあった時のやり方だと.onでevent drivenができたが,firestoreには .onが存在しないのでerrになる.

db.pushもfirestoreではerrになる....

collection

なので let db = firebase.firestore(); db.collection("notes").get(). then(function(querySnapshot) {
のようにfirestoreの解決策を取る.

なお.get()までではcllで出しても

Promise {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: t

promiseが帰ってきてしまう.

thenでsnapShotを返しても

lm
rm
...

とかが帰ってくるので

    this.db.collection('notes').get()
      .then(snapShot => {
        snapShot.forEach(doc => {
          console.log(doc.data(),doc.id);
        });
      });

ここまでやらないとtableの配列は入手できない!!!

tableからgetして,thenでpromiseをforeachした後にdoc.data()までだす!

https://www.djamware.com/post/5bc50ea680aca7466989441d/reactjs-firebase-tutorial-building-firestore-crud-web-application

ここにcollectionを用いたcrudが書いてあった。 ここを参考にすると下記のようになる

Appのconstructor内に

this.ref = firebase.firestore().collection('notes');
    this.unsubscribe = null;
    this.state = {notes: []};

を書きnotesのpromse?をrefに入れる.
unsubscribeは不明.更新用の場所?
そしてstateに空のnotes配列を作成

constructorの後に

  onCollectionUpdate = (querySnapShot) => {
    const notes = [];
    querysnapShot.forEach(doc =>{
      const noteContent = doc.data();
      notes.push({noteContent: doc})
    });
    this.setState({notes});
  }

というupdateの関数を作り,querySnapshotを引数にとり,

componentDidMount() { this.unsubscribe = this.ref.onSnapshot(this.onCollectionUpdate); }

componentDidMountでthis.unsubscribeにさっきのrefがsnapShotされる時?をとる。そこで onCollectionUpdateでは boards配列を作って、doc.data()を title, desc, auther, の変数に入れdocとkeyもいれ boardsにpushしてsetStateする。

このunsubからのonSnapshotでのonCollectionUpdateが,前回のon child addedを 代用しているように見える.

しかしsetStateのところで

Error: Objects are not valid as a React child (found: object with keys {id, noteContent}). If you meant to render a collection of children, use an array instead.
    in h1 (at App.js:69)
    in div (at App.js:64)
    in div (at App.js:58)
    in App (at src/index.js:9)
    in StrictMode (at src/index.js:8)
▶ 25 stack frames were collapsed.
App.onCollectionUpdate [as next]
src/App.js:28
  25 |       noteContent,
  26 |     });
  27 |   });
> 28 |   this.setState({notes});
     | ^  29 | }
  30 | componentWillMount() {
  31 |   this.unsubscribe = this.ref.onSnapshot(

のエラーが出る. このままでは使えないようだ

https://reactjs.org/docs/lists-and-keys.html

をみてさらにフォロワー様に教えてもらって直せた

react public document
function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

として<li key = {hoge.toString() } >{ hoge } </li> でtagのナカに入れて,stringにしてる.
また,mapの結果自体を変数に入れて,returnは変数一つにしている

とりあえず

 this.state.notes.map(
      (note) => {
           return(
             <h1>{note.key}</h1>
           )
         }
      )
  Line 70:19:  Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>?

  68 |                 return(
  69 |                   <h1 key= {note.key}>{note.key}</h1>
> 70 |                   <h2 key= {note.key}>{note.noteContent}</h2>
     |                   ^
  71 |                 )
  72 |               }
  73 |             )

タグを複数返すとエラーが出た.

だそうだ,returnするもの自体にdivで括るsyntax sugarらしい

これで出せたが,console.logしてみるとnoteContentのナカにnoteContentが入った

{key: "notes", doc: n, noteContent: {…}}
key: "notes"
doc: n {lm: t, um: t, Rm: n, Am: false, Pm: false, …}
noteContent: {id: 1, noteContent: "hoge"}
__proto__: Object

入れる際の階層構造を正した

    querySnapshot.forEach(doc =>{
      const noteContent = doc.data().noteContent;
      notes.push({
        id: doc.id,
        doc,
        noteContent,
      });
    });

ただこれでもidがnotesになってるから,idにもdoc.data()のさらに下の
doc.data().idを入れる.(実装としておかしいか?)

これでとりあえず,firestoreの値をReactのstateに入れてcllすることができた.

ここでもkeyがないerrが出るが,return で返しているのはdivなので,divに入れたら 解決した

correct code (render)
          {
            this.state.notes.map(
              (note) => {
                console.log(note);
                return(
                  <div key= {note.id.toString()}>
                    <h1>
                      {note.id},
                      {note.noteContent}
                    </h1>
                  </div>
                )
              }
            )
          }

f:id:kei_s_lifehack:20200426080618p:plain

ようやくfirestoreからhtmlに出せた.

なおhtmlのclassを壊してるからレイアウトがない

Youtubeではに渡してNoteでrenderしてたから,それを真似る必要がある

またid順に読み込まれたりはしていないからfilterも必要

componentWillMountで書いていると警告がでた

react-dom.development.js:88 Warning: componentWillMount has been renamed, and is not recommended for use. See https://fb.me/react-unsafe-component-lifecycles for details.

* Move code with side effects to componentDidMount, and set initial state in the constructor.
* Rename componentWillMount to UNSAFE_componentWillMount to suppress this warning in non-strict mode. In React 17.x, only the UNSAFE_ name will work. To rename all deprecated lifecycles to their new names, you can run `npx react-codemod rename-unsafe-lifecycles` in your project source folder.

Please update the following components: App

not recommendだそうだ.下記のリンクを見てみると

fb.me

Unsafeになってるから

npx react-codemod rename-unsafe-lifecycles

でrenameできるらしい.だが新しいのどう使うか書いてないし,全然わからん放置.

まぁ最終的にはhookで書き直すからヨシ!

return(                           
  <div key= {note.id.toString()}> 
    <Note noteContent=            
      {note.noteContent}          
      noteId={note.id}            
      key={note.id}               
    />                            
  </div>                          
)                                 

Noteにkeyを渡す方式でいく

無事にfirestoreの値が綺麗に表示された!!

f:id:kei_s_lifehack:20200426080618p:plain

f:id:kei_s_lifehack:20200428151925p:plain

次は追加の処理をfirebase/databaseから ../firestoreに置き換える

ADD


constructorの作成

dJam

import firebase from '../Firebase';
...
class Create extends Component {

  constructor() {
    super();
    this.ref = firebase.firestore().collection('boards');
    this.state = {
      title: '',
      description: '',
      author: ''
    };
  }
.........

djamではCreateとして作成している, propsは渡していない.
さらにstateにtitle, desc ,author,をカラで初期化.

Wes

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

一方Wesのではpropsを渡して,newNoteContentのみを初期化し
handleとwriteをbindしている
propsを渡しているのはthis.props.addNoteを受け取るためか.

kaede

Appと同じようにここNoteFormでもthis.ref...でnotes tableから持ってきた.
writeNoteは置いておいて,AppのaddNoteだけ書き換える.

Wes

Wesのはrenderに

<input ...           onChange = {this.handleUserInput} />
<btn ...          onClick = {this.writeNote} >... 

と指定ElementでにonChange, onClick時に関数を発火させているが

dJam

  <input type="text" class="form-control" name="title" value={title} onChange={this.onChange} placeholder="Title" />

dJamではonHogeで直接処理を書き込んでいる.なのでbindする必要がないバウ.だからonChangeにthis.onChangeを入れている


dJam

handle input関数,onChange

dJam

  onChange = (e) => {
    const state = this.state
    state[e.target.name] = e.target.value;
    this.setState(state);
  }

stateの指定のものに入れるのではなく,stateの配列名を指定して, そこにtarget.valueを入れて,それをsetStateしている

Wes

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

userが入れるところはnoteの中身だけなので,変数噛ませないで直接 this.setStateで入れるところを指定して入れている.

よく見るとonChange(e)でとる方が再利用せいが高い.

writeNote, onSubmit

Wes

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

writeNoteではaddNoteに値を渡すのと,inputをemptyにするだけの処理になっている

dJam

  onSubmit = (e) => {
    e.preventDefault();

    const { title, description, author } = this.state;

    this.ref.add({
      title,
      description,
      author
    }).then((docRef) => {
      this.setState({
        title: '',
        description: '',
        author: ''
      });
      this.props.history.push("/")
    })
    .catch((error) => {
      console.error("Error adding document: ", error);
    });
  }

一方dJamではstateの各値をtitle, desc, author,に分割代入し,
this.refに全て追加してhistoryに/を追加している,謎
またerr字の処理も書いている

  render() {
    const { title, description, author } = this.state;

renderでも同様にしてstateから取り出している

kaede

wesの作品ではnoteにはnoteContentのdataしかなくて,idはarrの大きさ+1にした

f:id:kei_s_lifehack:20200429160255p:plain

DBへの追加完了!!

UX的にはGoogle DocsやkeepみたいにonChangeでDB自体の変更もやってみると 面白いかもしれない

またaddNoteでpush処理をしていて,NoteFormはaddNoteにnewNoteContentを 渡すだけなので,NoteFormにはthis.refは必要がなかった.

ここでloginしたuserごとにpushできないと完成にならない...と頭を抱えたが,とりあえずはlogin無視で一つのtableでRead, Create, Update, Edit, Deleteできるようにする.


連番idとcreated_at

arrのlength + 1を追加する分のidとしていたら

idやキーを配列の長さで取ると削除機能実装時に死ぬ

と教えてもらって代わりにcreated_atをkeyとする方式をとった

App.js > render

        <div className="notesBody">
          {
            this.state.notes.map(
              (note) => {
                console.log(note);
                return(
                    <Note noteContent=
                      {note.noteContent} 
                      key={note.created_at}
                    />     
                )
              }
            )
          }
        </div>

でこれでstateのcreated_atをkeyとして渡して

Note.jsx > render

        <p className="noteContent">
          {this.noteContent}
        </p>  

これでnoteContentのみ表示する

f:id:kei_s_lifehack:20200503114225p:plain

firestoreで const created_at = new Date(); で送ると このようにtimestampで保存される


delete

ШесのYoutubeでは

    this.database.on('child_removed', snap => {
      for(var i=0; i < previousNotes.length; i++){
        if(previousNotes[i].id === snap.key){
          previousNotes.splice(i, 1);
        }
      }

  removeNote(noteId){
    console.log("from the parent: " + noteId);
    this.database.child(noteId).remove();
  }

                <Note noteContent={note.noteContent} 
                noteId={note.id} 
                key={note.id} 
                removeNote ={this.removeNote}/>

になっている. removeNoteのbtnをcontentと共に出して

               <span className="closebtn" 
                      onClick={() => this.handleRemoveNote(this.noteId)}>
                      &times;
                </span>
    handleRemoveNote(id){
        this.props.removeNote(id);
    }

idを渡してremoveNoteする

database.on(child_removed...になっているので,dJamの テキストを参考に...わからん

firebase公式だと

firebase.google.com

db.collection("cities").doc("DC").delete().then(function() {
    console.log("Document successfully deleted!");
}).catch(function(error) {
    console.error("Error removing document: ", error);
});

docのidを渡せばいいことがわかる.

このためにnotesの中身だけじゃなくてdoc自体もrefに入れておく必要があったのか

idは

            this.state.notes.map(
              (note) => {
                console.log(note.doc.id);

3YMpsV2NxfXWYWThpCl4
App.js:78 AS5v0YCUxqHX5cjeCeUR
App.js:78 Kds0WUyMGROVwV55frEE
App.js:78 zVFi3oudXwQG3vGXsVGa
App.js:78 3YMpsV2NxfXWYWThpCl4
App.js:78 AS5v0YCUxqHX5cjeCeUR
App.js:78 Kds0WUyMGROVwV55frEE
App.js:78 zVFi3oudXwQG3vGXsVGa

consoleにidが出てくる.担っている担っている

states.notesをmapのあと

でNoteにstateのidを渡す

Noteのconstructorで受け取る

this.id = props.id;
×
TypeError: Cannot read property 'doc' of undefined
removeNote
src/App.js:62
  59 | }
  60 | removeNote(id) {
  61 |   console.log(id);
> 62 |   this.ref.doc(id).delete.then(function() {
     | ^  63 |     console.log('deleted');
  64 |   }).catch(function(error) {
  65 |     console.error('error!!!!',error);
View compiled
Note.handleRemoveNote
src/Note/Note.jsx:16
  13 |   this.handleRemoveNote = this.handleRemoveNote.bind(this);
  14 | }
  15 | handleRemoveNote(id) {
> 16 |   this.props.removeNote(id);
     | ^  17 |   console.log('remove',id);
  18 | }
  19 | render(props) {
View compiled
onClick
src/Note/Note.jsx:23
  20 | return(
  21 |   <div className = 'note fade-in'>
  22 |     <span className='clsebtn'
> 23 |       onClick={()=> this.handleRemoveNote(this.id)}
     | ^  24 |     >
  25 |         &times;
  26 |     </span>

わからない, idが渡せない

Kindleの本が表示できないエラーを解決した

問題

Amazon kindle for Mac のアプリをダウンロードして、ログインした。

しかし購入済みの本が一つも表示されない。

amazon.co.jp ではなく amazon.com にログインしてしまう。

解決策

メールアドレスではなく電話番号のログインを試す。これで一度解決できた。

それでもダメだった場合、 ログイン時に切り替えられる。

f:id:kei_s_lifehack:20211005171131p:plain

これがデフォルトの画面で、ここでログインすると US に飛ばされてしまう。

f:id:kei_s_lifehack:20211005171208p:plain

f:id:kei_s_lifehack:20211005171233p:plain

よく見ると、デフォルト以外の画面を選択できる

f:id:kei_s_lifehack:20211005171340p:plain

これで amazon.co.jp を選択すれば、無事日本版にログインできる

f:id:kei_s_lifehack:20211005171458p:plain

購入した本のリストが表示できた。

原因とまとめ

Amazon.co.jp ( JP ) とAmazon.com ( US )

これらは別のサービス。

ふたつを同じメールアドレスで登録してしまっているのが一つの原因

もう一つは英語設定で使っているため、デフォルトが US 版が出てくること

前者はパスワードを変更するか使っていないUS verのアカウントを削除することで完全に解決するらしい

後者はログインするときにドメイン名をよく確認し、切り替えられるボタンがないか探せば OK

g-stylusの逆求人に参加しました

f:id:kei_s_lifehack:20200314123427p:plain

交通費1kその場で支給で,local innovationのイベントより清算が楽だった.

人気がないのか,8 term中 5枠空きで,学生同士の情報交換枠になってしまった。

6枠空きだった学生と情報交換したら、やはりProfileの言語の欄がpoorだったからのようだ。

キャリアセレクトの逆求人と違って待機ではなく、待機の学生同士をマッチングさせて情報交換のタームを設けていた。しゅうかつ

Students

最初の大学院生はM1で,fintechの内定が決まっておりdjangoと bootstrapで作られた完成度の高い飲み会予定& Map API管理appを 公開していた.完成度高くて励みになる. bootstrapの削除と編集btnかわいいな

次の学生はVtuberのオススメアプリとApple Watch連携のサイクリング ルートレコメンドアプリを作成してる動画編集者だった,同じ会社選考中で草.

三人目の子とはfirebaseやプログラミング経験年数5年以上募集のところ の愚痴言いながらもくもく会してたw jqueryでfirebase動いた

面談企業

レイスグループ

GA Technologys

www.ga-tech.co.jp

f4samurai

ソシャゲ会社.

www.f4samurai.jp

Bootstrap Example

why

FirebaseのDBの使用に,デザインコストをかけない手段として

Bootstrap4のTable-resonsiveとFormを検討した.

導入

cdnのlinkをstyleに記述する

Reactではnpm i で入る.cdnよりも組み込んだ方が動作が速い

blog.logrocket.com

Reactではこれの通りにindex.jsでimportしたら使えた.

form form-control

<form>
  <div class="form-group">
    <label for="exampleInputEmail1">Item Name</label>
    <input type="email" class="form-control" id="nameForm" 
    placeholder="Enter Name">
  </div>
</form>

f:id:kei_s_lifehack:20200314035940p:plain

divにform-group, label forにexmaple Input Email1,

classにform-control.

labelはあった方が間がつまらない

ただこのままだと一番右まで伸びていく.

<form>
  <div class="form-row">
      <div class="col-7">
        <input type="text" class="form-control" id="nameForm" 
        placeholder="Name">
      </div>
      <div class="col">
        <input type="text" class="form-control" id="nameForm" 
        placeholder="Purpose">
      </div>
      <div class="col">
        <input type="text" class="form-control" id='price'
        placeholder="Price">
      </div>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

col7, col, col,

で 7:1:1で並べられる

Align Center

f:id:kei_s_lifehack:20200314041254p:plain

Bootstrap実装前の状態がこれだが

f:id:kei_s_lifehack:20200402050025p:plain

単にこれにform-controlを入れると長くなってしまう

f:id:kei_s_lifehack:20200402050108p:plain

containerにcol-lg-1を入れると狭くできるが,

input がcenterに寄らない

もちろん3だともう少し広くなるだけ.

f:id:kei_s_lifehack:20200402052057p:plain

mx-autoをつけるとFormも中央に寄った

f:id:kei_s_lifehack:20200402052223p:plain

btn

btn btn-primaryをつけると綺麗になる

btnで丸く, primaryでいい色に

幅をformのように広くするやり方はわからん btn-group, btn-group-justifiedは効果なし

btn-lgで大きくはできる.広くfitはできない

table

<div class="table-responsive">
  <table class="table" id='table'>
    <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">name</th>
      <th scope="col">price</th>
      <th scope="col">purpuse</th>
    </tr>
    </thead>
    <thead id="usercol">
    <tr>
      <th scope="row">num</th>
      <td>Larry</td>
      <td>500</td>
      <td>@twitter</td>
    </tr>
    </thead>

  </table>
</div>

f:id:kei_s_lifehack:20200315122824p:plain

動的な追加はjqのappendtrごと挿入することで実装できる

なおそれで作ったらxvideoのscript埋め込まれて笑った h()見たいなの入れないとな

.table-responsiveはスマフォでも綺麗に見れる,bootstrap最高

getbootstrap.com

maring, padding mb-2

getbootstrap.com

marginがm, padding がp, leftがl, topがt, bottomがb,

0-5で調整,それらをまとめて使う

mb-2でmargin bottom2として読まれる.

mx-autoで簡単に中央揃えされるはず??うまくいかない.

text-centerではほぼうまくいった

mdbootstrap.com

font

text-primaryでbtn-primaryと同じいい色になる

f:id:kei_s_lifehack:20200402052546p:plain

www.tutorialrepublic.com

font sizeはh1h2を付け足すことで調整する

jquery basic method examples

text()

      <p id="tgt">02.20</p>

の02.20を

let target = $('#tgt').text()
console.log(target);

で取得できる.タグの中身?のテキスト..val()と違う.

val()

その名の通りinputのvalueを取れる.

      <input type="text" id = 'nameForm' value = 'default'/>
let inputval = $('#nameForm').val();
console.log(inputval);

これでvalueのdefaultが出力される.

click()

    $("button").click(function(){
        alert("button");
    }); 

でalertは出るが,cllだと出ない $(document).ready(function() { } は必要ない?

jquery

www.w3schools.com

$(function() {
 $("button").click(function(){
    $("p").hide();
  });
});

のように$('hoge)で要素を指定

.clickでイベント指定

$('p')で要素を指定

.hideで実行を指定

する

mouseenter() ,mouseleave(),などもある

$("p").on("click", function(){

でonを使ってもclickを組める

hideとshowとtoggleで隠せる

$("#btn1").click(function(){
  alert("Text: " + $("#test").text());
});

とid指定でbtn clickで発火せるのが簡単

$("div").text(); で中身を観れる

add html

jQuery Set Content and Attributes

$("#btn1").click(function(){
  $("#test1").text(function(i, origText){
    return "Old text: " + origText + " New text: Hello world!
    (index: " + i + ")";
  });
});

のようにidのtextにreturn で返すことで中身を追加できる

original text の中身がどんどん増えていく

でもこれだと見た目のHTML 要素に追加することはできてもfirebaseに変数を 介して追加することはできないし,画面の更新もできない

sql injection

firebaseのfirestoreからdataを持ってきてappened()でhtmlに 追加したらxvideosが開くリンクを入れられてしまったw

scriptを防ぐためにはhtmlEscape(), h()が一般的だがjsでは存在しない.

なのでcreateTextNode()で防げる?

stackoverflow.com

防げたけど何も出ない

f:id:kei_s_lifehack:20200315150640p:plain

f:id:kei_s_lifehack:20200315150640p:plain

こちらの回答にある関数定義を使ってみる