firebaseでGoogle AuthEntication
firebaseのAuthEnticationを触ってわかったことのメモ。
src/firebase.ts
import * as firebase from "firebase/app"; import "firebase/auth"; const config = { // Project Overview -> アプリ -> 設定から }; firebase.initializeApp(config); export default firebase;
Auth.tsx
import * as React from "react"; import firebase from "./firebase"; const Auth: React.FC = () => { const [user, setUser] = React.useState<firebase.User | null>(null); React.useEffect(() => { const watcher = firebase.auth().onAuthStateChanged(user => { setUser(user) } return () => { watcher(); } }, [setUser]); return( {user ? ( <button onClick={() => firebase.auth().signOut()}> logout </button> ) : ( <button onClick={login}> login </button> ) } ); }; const login = () => { const provider = new firebase.auth.GoogleAuthProvider(); firebase.auth().signInWithPopup(provider).then((result) => { // なんか処理 }).catch(error => { // エラー処理 }); }; export default Auth;
firebase.auth().onAuthStateChanged(…)
はfirebase.auth().currentUser
でも代用できるっぽい。
参考
https://firebase.google.com/docs/web/setup?authuser=0
https://firebase.google.com/docs/auth/web/start?authuser=0
https://firebase.google.com/docs/auth/web/manage-users?hl=ja
Twitter4jでタイムラインを取得する
ScalaでTwitter4jを使ってUserTimeline (特定のユーザーのツイート)を取得したメモ。HomeTimeineとかの他のタイムラインを取得するのもおんなじ感じでいけそう
UserTimelineの取得
import scala.collection.JavaConverters._ val twitter = new TwitterFactory().getInstance() // ConsumerKey, ConsumerSecretは自分で用意したものを使う twitter.setOAuthConsumer(ConsumerKey, ConsynerSecret) // 認証されたAccessTokenをセットする twitter.setOAuthAccessToken(accessToken) // userTimelineの取得 twitter.getUserTimeline(accessToken.getUserId).asScala
twitter.getUserTimeline()
の帰り値にscala.collection.JavaConverters._
のasScala
を呼び出すと、Seq[twitter4j.Status]
にすることができる。
TwitterFactoryのgetInstance()
の引数にはAccessTokenを取ることができるけど、そうするためにはtwitter4j.properties
ファイルにOAuthの認証情報を書いておくことが必要?
Pagingについて
パラメータ | 内容 |
---|---|
page | 何ページ目かについて |
count | 1ページあたりの件数 |
since_id | 指定したid以降のツイートを取得 |
max_id | 指定したid以前のツイートを取得 |
自分の指定したいパラメータをとるメソッドがオーバーロードされていなくても、setMaxId(Long)
やsinceId(Long)
メソッドを呼び出すことでパラメータを定義したり上書きすることができる。
まとめ
getUserTimeline()
の帰り値のResponseList
の扱い方がよくわからなくてハマったのでメモとして残しました。Pagingのパラメータは基本的にpageだけ(1ページの表示数を変えたいならcountも)で良さそうですね
参考
Frontend Bootcampを読む Step1-07
Microsoftが公開していたFrontend Bootcampを読み進めていくメモ
自分なりの適当な翻訳なので間違いがあるかもしれません。
また公開されたばかりで現在進行形で更新されているので僕が読んだ時とは内容が少し変わっているかもしれません。
Step1-07: Types and creating a UI-driven state
これまでで、アプリのstateによって変わるUIを作りました。ですが、まだUIからstateを変更することができないので、変更できるようにする機能を実装する必要があります。これは、TodoHeaderで見たように、setState
を呼び出す関数によって行われます。その後、stateの値は子Componentにpropsとして渡されます。
このワークショップのパート2では、propsを使って明示的に渡すことなくそれらの関数を使う方法を学びます。
これがReactの中心的な"ビジネスロジック"であり、基本的な"CRUD"操作を処理します。Create,Read,Update,Deleteのすべての関数を書くことについてはまだ説明していませんが、デモのTodoAppにすでに実装してあり、Componentに渡されていることがわかります。
Intro to TypeScript
TodoApp Componentを見てみると、propsが、長くなっているのではなく、とても複雑になっていることがわかります。様々な関数、todosオブジェクト、フィルタの文字列を送っています。
アプリケーションが大きくなるにつれて、関数や、todosの内容を覚えておくことが難しくなります。また、JavaScriptは動的型付け言語なので、todosの値を、TodoList内の配列に変えたい場合、JavaScriptは大丈夫でしょう。ですが、TodoListItemsが、オブジェクトを期待していたなら、アプリケーションは壊れてしまうでしょう。
これら2つの理由で、業界は強く型付けされたアプリケーションを書くように移行しています。そしてたくさんの人が移行するためにTypeScriptを使っています。
TypeScript is a superset of JavaScript that compiles to plain JavaScript.
TypeScriptのウェブサイトに書いてあるように、TypeScriptはJavaScriptにコンパイルされるJavaScirptのスーパーセットです。
もしSassを使ったことがあるなら、あなたはこの概念に精通しているでしょう。すべての有効なCSSが有効なSassであるように、すべての有効なJavaScriptは有効なTypeScriptです。これが、練習問題がjsとjsxの代わりにtsとtsxで書かれていた理由です。
TypeScriptを使ってComponentのpropsを明確にし、将来の後戻りを防ぎましょう。
Demo
最も多くのデータフローを持っているTodoListから始めましょう。TodoListItemにcompleted
を渡しているだけなので、TodoListはインタラクティブなUIは持っていません。ですが、すべて正しく渡されていることを確認するためにpropsインターフェイスを書くことができます。
Writing TodoListProps
TodoAppを見ると、TodoListが3つのprops(filter
,todos
,complete
)を持っていることがわかります。TodoListProps
というtodoListのporopsを表すインターフェイスを作ります。
// TodoList.tsx interface TodoListProps { filter: any; todos: any; complete: any; }
今は
any
を使用しています。これによって安全性が得られるわけではありませんが、このComponentに渡す有効なpropsの名前を指定できます。
インターフェースを書いたら、それをComponentに追加してください。
export class TodoList extends React.Component<TodoListProps, any>
<>
の最初の値はpropsのインターフェイス用で、2つ目の値はstate用です。
これで、型付きのComponentが作成できました。TodoAppに戻り、propsの名前を変更するとどうなるのかを見てみましょう。
Adding type safety
今のところ、propsの名前を指定しただけで、それらの型は指定していません。まずは、filter
を、型安全にしましょう。
Filter Type
filter
がオブジェクト、配列、関数ではないことがわかっているので、filter
が常に文字列であるべきだと指定することができます。
interface TodoListProps { filter: string; todos: any; complete: any; }
さらに、filter
は3種類の値にしかならないことがわかっているので、filter
を共用型(union type)で明示的にすることができます。
interface TodoListProps { filter: 'all' | 'active' | 'completed'; todos: any; complete: any; }
TodoAppに戻り、TodoListのfilter
を別のものにしてみてください。もし、VS Codeを使っているならエディタから、またファイルを保存したらコマンドラインからエラーが出るでしょう。
Complete Type
omplete propはデータではなく関数です。ですがTypeScriptではデータだけでなく関数型も扱うことができます。
interface TodoListProps { filter: 'all' | 'active' | 'completed'; todos: any; complete: (id: string) => void; }
関数の場合は渡されるパラメータと返される値の型を書きます。上の例では、stringのidを引数にとり、voidを返します。voidが意味するのは、返り値がないということです。
戻り値が指定していない場合、JavaScriptの全ての関数はundefinedを返しますが、戻り値の型としてvoidを宣言すると、関数から値を返そうとするとTypeScriptがエラーを出します。
Todos Type
todos propは、オブジェクトです。インターフェイスは次のようになります。
interface TodoListProps { filter: 'all' | 'active' | 'completed'; todos: { [id: string]: { label: string; completed: boolean; }; }; complete: (id: string) => void; };
[id: string]
は配列を示すわけでわなく、オブジェクトのインデックスシグネチャです。
これで、インターフェイスが完成しました。filter === 'all'
のallを変更してみてください、そしたらVS Codeがそれは常にfalseになると表示するでしょう。JacaScriptだった場合、その行にタイプミスがあったら、なぜフィルターが機能しなかったかの理由がわかりません。
Sharing types
Componentのほとんどが、todos
とfilter
の型を指定する必要があります。なので、TypeScriptを使用してファイル間で型を共有しましょう。既にTodoApp.types.ts
ファイルにこれらの型を書き出し、エクスポートしているので、それらをインポートして使いましょう。
import { FilterTypes, Todos, CompleteTodo } from "../TodoApp.types"; interface TodoListProps { complete: CompleteTodo; todos: Todos; filter: FilterTypes; }
Writing TodoListItemProps
TodoListItemを見ると、label
とcompleted
が既にTodoItemインターフェイスで定義されていることがわかります。TodoListPropsにTodoItemインターフェイスを継承して再利用することができます。
import { CompleteTodo } from "./TodoApp.types"; interface TodoListItemProps extends TodoItem { id: string; complete: CompleteTodo; }
TodoListItemPropsは、4つのプロパティ(id
, complete
, completed
, label
)を持つインターフェイスです。
次に、propsをrenderに取り込むことができます。
const { label, completed, complete, id } = this.props;
そしたら、inputのonChangeイベントを使ってコールバックを書きます。シグネチャの中でidがstringだと宣言しているので、idを渡します。
コールバックはpropsとしてComponentに渡される関数です。
<input type="checkbox" chacked={completed} onChange{() => complete(id)} />
propの名前と関数名が偶然同じですが、これは必須ではありません。
todoがonChangeを起動しているので、クリックしてアプリがどのような動作をするのかみてください。Footerのテキストは未完了のTodoの数に基づいているので、Footerは新しいstateを反映するために自動的に更新されます。
Exercise
まだアプリを実行していない場合はfrontend-bootcampフォルダのルートからnpm start
を実行して起動してください。動作を確認するためには、1日目のstep7の"exersice"をクリックしてください。
TodoFooter
- TodoFooterを開き、
TodoFooterProps
を書いてください。それはclear
とtodos
の2つの値を持ちます。このインターフェイスは関数のComponentでは次のように使用します。(props: TodoFooterProps
) props.clear
を呼び出す_onClick
関数を作ってください。- TodoFooterはクラスではないので、
_onClick
は戻り値の前のconst格納する必要があります。 - このクリックハンドラを定義するのにアロー関数を使ってください。
- TodoFooterはクラスではないので、
_onClick
をボタンのonClick
に割り当ててください。TodoFooterはクラスではないのでthis
を使う必要はありません。- この機能を試してみてください。いくつかのtodosを完了したら、
Clear Completed
ボタンをクリックします。
TodoHeader
TodoHeaderを開き、
addTodo
,setFilter
,filter
を含むTodoHeaderProps
を書いてください。そしてクラス宣言の最初のanyと置き換えてください。このComponentはstateを持っています。
TodoHeaderState
を書き、2つ目のanyと置き換えてください。各filterボタンに
_onFilter
を割り当ててください- onClickに新しいパラメータを追加することはできませんが、イベントターゲットから情報を取得することはできます。
- これもアロー関数にするのを忘れないでください
送信ボタンから
_onAdd
を呼び出せるようにしてください。この機能を試してみてください。todoを追加、フィルターすることができるでしょう。
// TodoFooter import React from 'react'; import { Todos } from '../TodoApp.types'; interface TodoFooterProps { clear: () => void; todos: Todos; } export const TodoFooter = (props: TodoFooterProps) => { const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length; const _onClick = () => { props.clear(); }; return ( <footer> <span> {itemCount} item{itemCount === 1 ? '' : 's'} left </span> <button onClick={_onClick} className="submit"> Clear Completed </button> </footer> ); }; // TodoHeader import React from 'react'; import { FilterTypes } from '../TodoApp.types'; interface TodoHeaderProps { addTodo: (label: string) => void; setFilter: (filter: FilterTypes) => void; filter: FilterTypes; } interface TodoHeaderState { labelInput: string; } export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> { constructor(props) { super(props); this.state = { labelInput: '' }; } render() { const { filter } = this.props; return ( <header> <h1>todos - step1-07 exercise</h1> <div className="addTodo"> <input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" /> <button className="submit" onClick={this._onAdd}> Add </button> </div> <nav className="filter"> <button className={filter === 'all' ? 'selected' : ''} onClick={this._onFilter}> all </button> <button className={filter === 'active' ? 'selected' : ''} onClick={this._onFilter}> active </button> <button className={filter === 'completed' ? 'selected' : ''} onClick={this._onFilter}> completed </button> </nav> </header> ); } _onFilter = evt => { this.props.setFilter(evt.target.innerText); }; _onChange = evt => { this.setState({ labelInput: evt.target.value }); }; _onAdd = () => { this.props.addTodo(this.state.labelInput); this.setState({ labelInput: '' }); }; }
参考
frontend-bootcamp/step1-07/exercise at master · Microsoft/frontend-bootcamp · GitHub
Frontend Bootcampを読む Step1-06
Microsoftが公開していたFrontend Bootcampを読み進めていくメモ
自分なりの適当な翻訳なので間違いがあるかもしれません。
また公開されたばかりで現在進行形で更新されているので僕が読んだ時とは内容が少し変わっているかもしれません。
Step 1-06 Demo: Creating a State-Driven UI
Reactのデータは、トップダウンのようにComponent階層を上から下に伝わっていきます。stateを持つComponentのみがそのstateを変更できます。UIインタラクションが起きた時、stateを持つコンポーネントはstateの変更を受け取るために、イベントハンドラをUI Componentに渡す必要があります。
"Thinking in React"のステップ3では、アプリケーションに必要な"変更可能なstateの最小セット"を考えることが必要であると書いてあります。このデモでは、最小のstateをアプリケーションに追加し、そのデータからUIを操作します。またstateを変更できるようにします。stateを変更する方法(関数とか)は、UI Componentを通してカスケードダウンします。reconciliationでstateが変化した時に、UIの何が変更されるかを把握できます。
Adding state to TodoApp
TodoApp
クラスの中に、todos
とfilter
というstateを作成します。未完了のTodoを数えるのは、completeフィールドがfalseに設定されているtodos
の数を数えれば計算できるのでstateを作る必要はありません。
// TodoApp constructor(props) { super(props); this.state = { todos: { '04': { label: 'Todo 4', completed: true }, '03': { label: 'Todo 3', completed: false }, '02': { label: 'Todo 2', completed: false }, '01': { label: 'Todo 1', completed: false } }, filter: 'active' }; }
場合によってはTodosを配列にした方が簡単になりますが、この場合、オブジェクトを利用した方が最終的には高性能になります。
Passing state through to UI
filter
とtodos
をComponentに渡します。
// TodoApp render() { const { filter, todos } = this.state; return ( <div> <TodoHeader filter={filter} /> <TodoList todos={todos} filter={filter} /> <TodoFooter todos={todos} /> </div> ); }
State-driver TodoList
TodoListを見ると、すでにpropsをfilterとtodosという変数に渡し、さらにfilter
のstateによってフィルタ処理されたtodosの配列を返す処理もしています。これらを使って、TodoItemをレンダリングします。
todos[id]
は渡されたidに一致するtodoを返し、スプレッド演算子(…)はlabel={todos[id].label} completed={todos[id].comleted}
と同じです。
return ( <ul className="todos"> {filteredTodos.map(id => ( <TodoListItem key={id} id={id} {...todos[id]} /> ))} </ul> );
State-driven and stateful TodoHeader
TodoHeaderでは、filter
stateを渡すだけではなく、コントロール内で状態を維持したいという場合があります。幸い、Reactにとってこれは全く問題ありません。最初にstateを扱いましょう。
Conditional class names
CSSのスタイルでは、ビジュアルをクラスを追加または削除することによって適用されます。filter
を利用して、条件付きでクラスを追加し、正しい装飾をすることができます。
<nav className="filter"> <button className={filter === 'all' ? 'selected' : ''}>all</button> <button className={filter === 'active' ? 'selected' : ''}>active</button> <button className={filter === 'completed' ? 'selected' : ''}>completed</button> </nav>
三項演算子
condition ? expressionIfTrue : expressionIfFalse
はReactでよく使われています。各式はclassNameやJSXのelementの文字列になる可能性があるからです。
Adding a controlled imput
Reactでは、<input>
,<textarea>
,<select>
などのform要素は未制御の入力(UnControlled input)または制御された入力(Controlled input)として使用できます。
未制御では、現在の値をform要素が内部的に維持し、ユーザーの操作(テキストの入力、オプションの選択など)に基づいて更新します。送信時など、コードは必要な時のみに、入力から値を取得します。イメージとしてはプレーンなHTMLのformです。
制御された場合はpropsから現在の値を取得し、コールバックを利用してユーザーによって行われた変更を親Componentに送ります。入力の値は、親Componentがコールバックに応答して、入力のpropsを更新するまで変わりません。
未制御と制御のものとを区別するのは、form Componentを書くときや使う時に理解することが大切です。詳しくはこの記事を参照してください。
TodoHeader Componentのテキストフィールドを制御に変更してみましょう。制御された入力にするには、デモですでに説明された2つのことが必要です。
入力値を保持するためにstateを作る
javascript this.state = { labelInput: "" };
値を更新するためのコールバック関数を作る
javascript _onChange = evt => { this.setState({ labelInput: evt.target.value }); };
これらを適用することで、未制御の入力を制御された入力に更新することができます。
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
React Dev Toolsがインストールされている場合はそれを確認しがならLabelInputを確認してください。
Exercise
もしアプリケーションを起動していないのなら、frontend-bootcamp
のルートでnpm start
を実行してください。結果を確認するにはday1 step6にある"exercise"をクリックしてください。
TodoFooter
itemCount
を利用して、現在のアイテム数を表示してください。- 三項演算子を利用し、
itemCount === 1
であるかどうかで"item"と"items"を切り替えるようにしてください。
TodoListItem
- 分割代入を利用して
label
,completed
を代入してください。 - テキストを
label
に、checked属性をcompleted
にしてください。
// TodoFooter export const TodoFooter = (props: any) => { const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length; return ( <footer> <span> {itemCount} item{itemCount === 1 ? '' : 's'} left </span> <button className="submit">Clear Completed</button> </footer> ); }; // TodoListItem export class TodoListItem extends React.Component<any, any> { render() { const { label, completed } = this.props; // onChangeは実行時に出るWarningを防ぐために書いてます。 return ( <li className="todo"> <label> <input type="checkbox" checked={completed} onChange={() => undefined} /> {label} </label> </li> ); } }
Frontend Bootcampを読む Step1-05
Microsoftが公開していたFrontend Bootcampを読み進めていくメモ
自分なりの適当な翻訳なので間違いがあるかもしれません。
また公開されたばかりで現在進行形で更新されているので僕が読んだ時とは内容が少し変わっているかもしれません。
Step1-05 Demo: Building a Static Page
Thinking in Reactで説明されている手順に従って、TODOアプリを作っていきます。
まず最初に、アプリケーションをCompoentの階層に分割していきます。このアプリケーションでは、4つに分割します。
- TodoHeader
- TodoList
- TodoListItem
- TodoFooter
このアプリケーションのモックアップを、step1-05/TodoApp.html
で確認することができます。
TodoHeader
Componentは全てsrc/component
ディレクトリに格納するので、ディレクトリを作成してください。作ったら、TodoHeader ComponentをTodoHeader.tsx
というファイルに作ります。.tsx
拡張子は、このファイルがTypeScript + Reactでコードを書いていると表します。
TypeScriptについては後で説明されます。今わかるのは、TypeScriptファイルにJavaScriptを書くことができるということです。
import React from "react"; export class TodoHeader extends React.Component<any, any> { render() { return ( <header> <h1>todos</h1> <div className="addTodo"> <input className="textfield" placeholder="add todo" /> <button className="submit">Add</button> </div> <nav className="filter"> <button className="completed">all</button> <button>active</button> <button>completed</button> </nav> </header> ); }; }
Reactでは、
class
をclassName
にする必要があります。
TodoListItem
要素が繰り返し表示されている場合は、基本新しいComponentを作った方がいいです。propsを使えば、それらの要素を単一のComponentにすることができます。TodoListItemが、それに当てはまります。
import React from 'react'; export class TodolistItem extends React.Component<any, any> { render() { return ( <li className="todo"> <label> <input type="checkbox" /> Todo 1 </label> </li> ); } }
これは、クラスの代わりに関数として作ることもできます
export const TodoListItem = (props) => {}
Exercise
TodoFooter
- TodoFooter Componrntを
component
ディレクトリに作ってください。<footer>
タグとその子要素をstep1-05/TodoApp.html
からコピーします。TodoFooterは関数またはクラスです。 class
をcalssName
に変更してください。
TodoList
- TodoFooterと同じようにTodoList Componentを追加してください。クラスと関数どちらでもいいです。
- TodoListItemをインポートし、
- の内側に4つ追加してください。
- オプションでArrayのmapなどを利用して作成してみてください。
App.tsx
これらのComponentをApp.tsxにインポートし、TodoHeaderの下に配置してください。
// TodoFooter export const TodoFooter = props => { return ( <footer> <span>4 items left</span> <button class="submit">Clear Completed</button> </footer> ) } // TodoList import { TodoListItem } from "./TodoListItem; export const TodoList = props => { return ( <ul className= "todos"> { [1, 2, 3, 4].map((i) => <TodoListItem key={i} text={"Todo " + i.toString()} />)} </ul> ) }; // TodoListItem <input type="checkbox" /> {this.props.text} // App.tsx import React from "react"; import { TodoHeader } from "./components/TodoHeaderr"; import { TodoList } from "./components/TodoList"; import { TodoFooter } from "./component/TodoFooter"; export class TodoApp extends Reract.Component<any, any> { render() { return ( <div> <TodoHeader /> <TodoList /> <TodoFooter /> </div> ); } }
参考
Frontend Bootcampを読む Step1-04
Microsoftが公開していたFrontend Bootcampを 1-04から読み進めていくメモ
自分なりの適当な翻訳なので間違いがあるかもしれません。
また公開されたばかりで現在進行形で更新されているので僕が読んだ時とは内容が少し変わっているかもしれません。
上のリンクのREADMEに沿って環境を整えてください。
Step1-04: Introduction To React Demo
このデモでは、クリック数とカウントを表示するシンプルなカウンターを作ります。
CodePenを使って始めましょう。
React Hello World
ReactDOM.render(<p>Hello World</p>, document.getElementById('app'));
ReactDOM.render()
この関数を使ってコードを表示します。2つのパラメータを取ります。
1つはページに配置するコンテンツ(ここでは
<p>Hello World</p>
)2つ目はコンテンツを配置したい場所(ここでは
document.getElementById('app')
)です。
Writing React Component
ReactのComponentはアプリケーションの一部を返すコードです。これには、HTML、CSS、JavaScriptを組み込むことができます。
Componentは2つの方法で作成することができます。
1つはReact.Component
クラスを継承するJavaScriptのクラスを利用する方法です。
JavaScriptのクラスは、拡張可能なコンテナ内にメソッド(関数)とProperties(値)を集めることができます。React.Componentは、renderを含むいくつかのメソッドを使えるようにするので、拡張しています。
class App extends React.Component { render() { return <p>Hello World</p>; } }
Componentは、propsを受け取ってJSXを返す関数として書くこともできます。
const App = props => { return <p>Hello World</p>; };
Hello World
をAppのrenderに移動したので、`ReactDOM.Render()を次のようにできます。
ReactDOM.render(<App />, document.getElementById('app'));
React Componentは、HTMLタグと同じように記述することで再利用できます。
Props
どちらの方法でComponentを作っても、id
やhref
などのHTML属性と同じ構文を利用して追加のpropsを取り込むことができます。
<App text="Hello World" />
propsはComponentから、関数のprops.text
、またはクラスのthis.props.text
を通してアクセスすることができます。
// 関数の場合 const App = props => { return <p>{props.text}</p>; }; // クラスの場合 class App extends React.Component { render() { return <p>{this.props.text}</p>; } }
propsを使うと、同じComponentの複数のインスタンスを異なるpropsで使うことができるため、Componentをより再利用しやすくなります。
ReactDOM.render( <div> <App text="Hello World" /> <App text="How are you doing?" /> </div>, document.getElementById('app') );
レンダリングする関数は1つの要素しか返すことができないため、2つのApp Componentをdivでラップする必要があります。
const App = props => { <p>{props.text ? props.text : "oops!"}</p>; };
Destructuring Props
関数内でprops.text(またはクラス内でthis.props.text)を繰り返し書くのは冗長です。なので、textに変数を割り当てることができます。
const App = props => { const text = props.text; return <p>{text ? text : 'you missed something'}</p>; };
これは、単一のpropsに対しては便利です。しかし、Componentが複雑になるにつれてコードはこうなります。
<MyComponent open={false} count={5} text="Hi there" items={['cat', 'dog', 'bird']} config={{ start: 1, end: 10, autoStart: true }} /> // Component内 const open = props.open; const text = props.text; const count = props.count; const items = props.items; const start = props.config.start; const end = props.config.end;
string以外の値は全て{}で囲んでJavaScriptとして渡します。
destructuringを使うことによって複雑なデータ型から個々の情報を1行で取り出すことができます。
const { open, text, count, items, config: { start, end } } = props;
今のはやり過ぎかもしれませんが、propsを追加することは簡単です。
const App = props => { const text = props.text; return <p>{text ? text : 'you missed something'}</p>; };
Cleanup
先に進む前に、ReactDOM.render
をリセットしてAppを返すだけにします。このReactDOM.render
関数は基本的にの無い単一のComponentのみを含みます。
次に、Counter
Componentを作ります。コードをを以下のようにしてください。
const App = props => { return <Counter text="chickens" />; }; ReactDOM.render(<App />, document.getElementById('app'));
Counter
の大文字に気をつけてください。HTMLの場合は大丈夫ですが、JSXでは区別します。React Componentの名前は一般的には対応するHTML要素の大文字の名前を使用することです。(Button, Select, Label, Formなど)
React State
Reactはstateというデータストアを各コントロールに指定することができます。UIをレンダリングするときに、stateの値を参照できます。また、アプリケーションが有効な間にstateを更新することもできます。
最近、Hooksという関数Componentにstateを追加する機能が追加されましたが、今現在見られるステートフルComponentのほとんどがクラスベースです。
Adding State
JavaScriptのクラスはconstructor
を利用してクラスをstateと共にインスタンス化します。それでは、Counter
という新しいComponentを作り、デフォルト値が0のclicks
stateを設定しましょう。
class Counter extends React.Component { constructor(props) { super(props); this.state = { clicks: 0 }; } }
- コンストラクタはComponentのpropsを受け取ります。
super(props)
は親クラスのコンストラクタを呼び出します。(この場合はReact.Component
)clicks
stateには、this.state.counter
を呼ぶことですぐにアクセスできます。また、this.setState({ clicks: 1 })
を呼び出すことによってstateを更新することもできます。
Creating out Counter
Counter Componentの目標は、clicksのボタンがクリックされた回数を追跡できるようにすることです。以下のコードを書き込みます。
render() { const { text } = this.props; const { clicks } = this.state; return ( <div> {text}: {clicks} <button>Click</button> </div> ) }
Writing our Button Click Handler
次のステップは、ボタンを押すとclickが増えるようにすることです。
慣例で、他のメソッドはrender()の下に配置されます。また、privateなメソッドはメソッド名の前にアンダースコアがつきます。
このメソッドはComponentのstateを更新し、1づつclicksの値を増やします。(setStateはオブジェクトの値のみを変更します。)
_onButtonClick = () => { this.setState({ clicks: this.state.clicks + 1 }); };
前の値が決定されるまでstateを更新しないように
this.setState(prevState => ({ counter: prevState.clicks + 1 });
と書くこともできます。
カウントを増やせるようになったので、ボタンに接続しましょう。
<button onClick={this._onButtonClick}>Click</button>
各Counterは、自身のstateを維持しています。なので、他の Counterに影響を与えずに、1つのCounter内のstateを変更できます。
Try it all out!
それぞれ異なるtextを使用してアプリのカウンターを2つにします。それらが自身のstateを維持していることがわかります。
Module Exports and Imports
step1-04/final/components/Counter.tsx
を開き、Counter Componentを見てください。
export class Counter extends React.Component { ... }
このファイルはCounter Componentを'named'エクスポートとしてエクスポートしています。これは次のようにインポートします。
import { Counter } from './components/Counter';
Default Exports
通常はnamedエクスポートを使いますが、次のようにデフォルト値をエクスポートすることもできます。
export default class extends React.Component { ... }
この場合、エクスポートに名前がないので、Componentをインポートするときに、好きなように名前をつけることができます。
import SomeCounterComponent from './components/Counter';
上の例ではインポート値を{}でラップしていません。これは実際には破壊的な例です。
Using a Button component
ボタンは最も一般的にかかれたComponentの1つです。カスタムボタンは、一般的なスタイルを抽象化したり、アイコンやその他の装飾を追加したり、メニューボタンなどの機能を増やすことができます。カスタムComponentを見てみましょう。
import React from 'react'; import './Button.css'; export const Button = props => { return ( <button className="Button" onClick={props.onClick}> {props.children} </button> ); };
参考
Reactのチュートリアルをやったので簡単に電卓を作った
Reactのチュートリアルを読んだので簡単に電卓をつくりました。
作ったやつ
ソースコード
本当にReactのチュートリアルの技術しか使ってないので解説とかはせず、作った後に考えて気づいたこととかを書こうと思います。
setStateについて
class Board extends React.Component { ... updateState( result = this.state.result, disp = this.state.disp, op = this.state.op ) { this.setState({ result: result, disp: disp, op: op, }); } ... }
Boardコンポーネント内にupdateState
というセッターメソッドを作って子コンポーネントに渡していました。でも、setState
の引数がオブジェクトなので、返り値がオブジェクトの関数を読んであげればもっと綺麗に書けるのかなって思いました。
// 適当に書くとこんな感じ calculate(op) { return { op: op } } this.setState(calculate(opelator));
updateState
に囚われてボタンパネルのコンポーネントButtons
にメソッドをたくさんつくっていましたが、そこらへんの処理を別ファイルに切り出してあげるとよさそうだと思います。
Stateを子コンポーネントに渡す
Board
のステータスを複数Buttons
に渡すのに、わざわざひとつづつ渡していましたが、propsでstate={this.state}
って感じにしてあげればステータスの数が少ない時はいいのかなって感じです。
// こんなのを <Buttons display={this.state.disp} result={this.state.result} /> // こうする <Buttons state={this.state} />
まとめ
ReactはHTMLに比べてプログラミングしてる感があって楽しいなって思います。
Reactの学習が一段落ついてTypeScriptをやり始めたらtsでリファクタリングしたいと考えています。