- 投稿日:2019-07-30T23:50:41+09:00
AmplifyでAuthしてみるときに詰まったこと
概要
基本的には このサイト を参考にさせていただいてほとんど完結しました。
しかし、詰まるところもあったので、その部分について書きます。詰まったこと
aws-amplify-reactが読み込めない
エラー発生箇所
import { Authenticator } from 'aws-amplify-react'発生したエラー
Could not find a declaration file for module 'aws-amplify-react'. '<path>' implicitly has an 'any' type. Try `npm install @types/aws-amplify-react` if it exists or add a new declaration (.d.ts) file containing `declare module 'aws-amplify-react';`ts(7016)参考にさせていただいたサイトでも同様のエラーが出たことが報告されていて、その解決法が書かれていたのですが、その解決法では解決しませんでした。
そこで、ググりました。
この GitHubのページ によると
aws-amplify-reactの型が定義されていないために起こるエラーであるそうです。.d.tsファイルに
declare module 'aws-amplify-react'
を追加するとエラーが消えました。ググってから気づきましたが、解決方法がエラーメッセージに出てましたね。
エラーメッセージをちゃんと読まずにGoogle検索しがちなのは良くない癖ですね。まとめ
このエラーは型が定義されていないときに起こるエラーであり、型の定義が見つからない時は、エラーメッセージに出てる通り
npm install @type/hoge
で型の定義を追加できればそれでよく、できない場合は今回のように自分で追加すれば解決できるようです。
- 投稿日:2019-07-30T18:00:49+09:00
【JavaScript修行】React,ステータスについて
https://ja.reactjs.org/docs/state-and-lifecycle.html
https://qiita.com/morrr/items/c32a4916d55373b64c70
https://mae.chab.in/archives/2956
こちらを参考にしながら今日も勉強いたします
タイマーの分割
function tick() { const element = ( <div> <h2>タイマー</h2> <p>{new Date().toLocaleTimeString()}.</p> </div> ); ReactDOM.render( element, document.querySelector('body') ); } setInterval(tick, 1000);setIntervalで1秒ごとにtickコンポーネントを更新しています。
これを分割したいのですが、今まで学んだことを使うとこうなります。function Clock(props){ return( <div> <h2>タイマー</h2> <p>{props.date.toLocaleTimeString()}.</p> </div> ); } function tick(){ ReactDOM.render( <Clock date={new Date()} />, document.querySelector('body') ); } setInterval(tick, 1000);でもこれだと、時間処理を毎秒更新する機能をClockに持たせることができていません。
Clockが自身を更新できるようにしたいです。
そのためにはまず関数コンポーネントからクラスコンポーネントに書き換えます。class Clock extend React.Component { render(){ return( <div> <h2>タイマー</h2> <p>{this.props.date.toLocaleTimeString()}.</p> </div> ); } }クラス変換で追加したrenderメソッドは更新が発生するたびに呼ばれます。
state
state・・・内部で状態を保持できる。
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h2>タイマー</h2> <p> {this.state.date.toLocaleTimeString()}.</p> </div> ); } } ReactDOM.render( <Clock />, document.querySelector('body') );・クラスコンポーネントの場合、引数をpropsにして、super(props)を呼び出す。
・stateの初期状態をコンストラクタで設定する。これでdateの情報をClockがもてるようになりました。
しかし、時間の更新の機能もコンポーネントに持たせたいですね。ライフサイクルイベント
まずは用語から。
マウント・・・コンポーネントが最初に描画される時。
アンマウント・・・コンポーネントから生成したDOMが削除される時。上記のような状態の変化(ライフサイクル)に合わせて発火するライフサイクルメソッドがReactには準備されている。
メソッド名 発火地点 componentWillMount() マウントされる直前 componentDidMount() マウントされた直後 componentWillReceiveProps() propsが変化した時 shouldComponentUpdate() state,propsが変更され再描画が走る前。trueで再描画される。 componentWillUpdate() 再描画される前 shouldComponentUpdate()がfalseで発火しない componentDidUpdate() 再描画されたタイミング 再描画後のDOMにアクセス可 https://www.to-r.net/media/react-tutorial09/
追加するメソッド①componentDidMount(){ this.timerID = setInterval( ()=> this.tick()こちらはマウント直後に発火します。
tick()
メソッドは後ほど記述します。
this.props
やthis.state
以外なら、this上に任意のデータを格納してOKです。追加するメソッド②componentWillUnmount() { clearInterval(this.timerID); }こちらはマウントされる直前に発火します。
これで前のsetIntervalをクリアできますね。追加するメソッド③tick(){ this.setState({ date:new Date() }); }
setState
・・・class componentのメソッド(なのでthisで呼び出せる)第一引数には更新後のstateの値をオブジェクト or 関数で渡す。
なので、流れとしては、
- componetDidMount()で1秒毎にtick()を呼ぶようにセット
- tick()でstateのdataを新しい時間になるように変更
- stateの変更によってrender()が走る。時間が描写される。
- 今後DOMからClockが削除される場合は、componentWillUnmount()が走ってタイマーが停止する。
ちょっとややこしいのでゆっくり追って理解しました。
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h2>タイマー</h2> <p>{this.state.date.toLocaleTimeString()}.</p> </div> ); } } ReactDOM.render( <Clock />, document.querySelector('body') );全部まとめるとこうですね。
ちゃんとタイマー機能をClockに分離することができました。stateについてもっと知る
禁忌!
stateを直接変更してはならない。
this.state.animal = '犬'; //ダメ this.setState({animal:'犬'}); //正しいコンストラクター以外ではsetState()を使うこと!
非同期に注意!
state・propsの更新は非同期に行われることがあるのでそれに注意しないといけない
→this.porpsとthis.state同士を依存させるのはダメthis.setState({ sum: this.state.sum + this.props.increment, }); //非同期だからうまく値が取れない場合がこの場合、
setState()
を以下の記述方法にする。this.setState((state,props)=>({ sum: state.sum + props.increment }));疑問...内部でどんな処理が行われて非同期を回避しているんでしょう。
いつか調べたいと思います。今日はちょっとドキュメント読み解きに手こずったので間違いがあるかもしれません,,,
ご指摘等お気軽にお願いします!
- 投稿日:2019-07-30T16:27:47+09:00
Javascriptの関数の引数でよく見る({ id })ってどういう意味?
VueやReactを書いていると、こんな感じの関数をよく見ます。
sample.vuemethods: { userData({ id }) { // 処理 } }Vuexのactionでも({ commit })という記述をよく見ますよね。
正直、初めて見たときは意味不明でした。引数に波括弧ってどういうこと?みたいな。
同じように思っている人も多い(はず)なので、以下でこの独特な記法について解説していきます。
上記の書き方はES6の分割代入の一種っぽい
分割代入とは、以下のようなものです。
const data = { id: 1, name: 'taro' } const { id, name } = data; console.log(id); // 1 console.log(name); // tarodataオブジェクトはidとnameというプロパティを持っています。代入したい変数名とプロパティ名が一致している場合、上記のように書くことで1行にまとめることが可能です。
関数の引数に出てくる波括弧もよく似たもので、上の考え方を少し応用すれば理解できるかと思います。
sample.vue<template> <div> {{ displayUserData(userData) }} // taroと表示される </div> </template> <script> export default { data() { return { userData: { id: 1, name: 'taro' } } }, methods: { displayUserData({ name }) { return name } } } </script>displayUserDataメソッドの引数は({ name })となっています。これは、引数として渡されたオブジェクトのプロパティにnameがあれば、それを利用するという意味です。
このメソッドを使う場合、上記のようにuserDataオフジェクトをそのまま放り込みます。userDataはnameプロパティを持っているので、この場合は'taro'が表示されます。
これは以下の書き方と同義です。
sample.vue<template> <div> {{ displayUserData(userData.name) }} // taroと表示される </div> </template> <script> export default { data() { return { userData: { id: 1, name: 'taro' } } }, methods: { displayUserData(name) { return name } } } </script>displayUserDataの引数から波括弧がなくなり、加えて呼び出し時にuserData.nameと、プロパティを指定しています。
ということは、({ commit })はどういう意味?
Vuexのactionsを定義する際、下記のような書き方をすることが多いかと思います。
sample.jsactions = { somethingAction({ commit }) { commit('somethingMutation') } }実は、上記についてはこのように書くこともできます。
sample.jsactions = { somethingAction(context) { context.commit('somethingMutation') } }Vuexのactionsはdispatchされると、contextオブジェクトを受け取ります。そしてcontextオブジェクトは、以下のようなプロパティを持っています。
{ state, rootState, commit, dispatch, getters, rootGetters }ただ、commitしか使わないケースが大半なので、({ commit })と書くことで簡略化することが多いかと思います。
上記の通り、contextオブジェクトはdispatchプロパティも持っているので、以下のような感じにすればactionから別のactionを呼び出すことも可能です。
actions = { somethingActions({ commit, dispatch }) { commit('somethingMutation') dispatch('otherAction') } }公式ドキュメントにより詳しく書かれているので、もっと詳しく知りたい人はそちらを見てください。。
まとめ
jsフレームワークのconfigファイルとかでもよく出てくる記法なので、理解しておくと便利です。
これらについては、「呼びされるときに呼び出し元からオブジェクトを渡される」ということを知っておくと、より理解しやすいかなと思います。