【React】Pessimistic UpdateとOptimistic Updateの違い
Pessimistic Updateとは?
Pessimistic Update(悲観的な更新)とは非同期通信が成功するか分からないので、成功or失敗するまで待ってから手元のDOMを更新する方法である。非同期通信の結果を待つ必要があるので非常に遅い。
// post = {id: 1, name: 'hoge'}のようなオブジェクト handleDelete = async post => { // posts/3のようなurlへdeleteメソッドでアクセス await axios.delete(`${apiEndpoint}/${post.id}`); // 非同期通信が終わってからstateを更新する // 引数で受け取ったpostを除外する新しい配列postsを作成 const posts = this.state.posts.filter(p => p.id !== post.id); this.setState({ posts }); //このタイミングでviewが再レンダリングされる }
Optimistic Updateとは?
Optimistic Update(楽観的な更新)とは非同期通信が成功することを前提としてローカルのリソースを先に更新することである。つまり、サーバー上のリソースの変更が成功したかどうかに関わらず、先にstate
を更新してDOMを更新するのである。await
でpromise
オブジェクトを待つ必要がないので、スピードが上がりUXが向上される。
handleDelete = async post => { const originalPosts = this.state.posts; // 引数で受け取ったpostを除外する新しい配列postsを作成 const posts = originalPosts.filter(p => p.id !== post.id); this.setState({ posts }); //このタイミングでviewが再レンダリングされる try { await axios.delete(`${apiEndpoint}/${post.id}`); } catch (ex){ // もし失敗するとviewが再レンダリングされて元に戻る alert('投稿の削除に失敗しました') this.setState({ posts: originalPosts }) } }
【React】コンポーネントを再利用できるようにするリファクタリング
例えばこのような2つのコンポーネントがある。これらのコンポーネントの問題点は何だろうか?
親コンポーネント
state = { users: [{ id: 1, name: 'rin' }, { id: 2, name: 'sin' }] } render () { <div className="container"> <ListGroup items={this.state.users} /> <div> }
子コンポーネント
const ListGroup = ({items}) => { return ( <ul className="list-group"> {items.map(item =>( <li key={item.id} className="list-group-item"> {item.name} </li> ))} </ul> ) }
答え:再利用できないこと
コンポーネントは再利用してナンボである。今回の例において何が良くないかと言うと、子コンポーネントが親からもらうオブジェクトの属性を決め打ちしてしまっていると言うである。つまり<li key={item.id} className="list-group-item"> {item.name}
という箇所である。item
のプロパティid
ではなく_id
だったら、name
ではなくuserName
だったら、再利用できないよね?という話である。上のコードは子と親が密結合なのである。
リファクタリング
親から子にpropsとしてデータを渡す時に、オブジェクトの属性名も一緒に渡す。
子ではブラケット記法([]
)をつかって動的に属性を変更する。こうすることによって、子コンポーネントの再利用が容易になる。
親コンポーネント
state = { users: [{ id: 1, name: 'rin' }, { id: 2, name: 'sin' }], languages: [ { number: 1, langName: 'JavaScript'}, { number: 2, langName: 'typeScript' } ] } render () { <div className="container"> <ListGroup items={this.state.users} textProperty="name" valueProperty="id"/> <ListGroup items={this.state.languages} textProperty="langName" valueProperty="number"/> <div> }
子コンポーネント
const ListGroup = ({items, textProperty, valueProperty}) => { return ( <ul className="list-group"> {items.map(item =>( <li key={item[valueProperty]} className="list-group-item"> {item[textProperty]} </li> ))} </ul> ) }
ListGroup
コンポーネントを再利用できるようになりました!
defaultPropsを設定してさらに見やすく
親から子へpropsでデータを渡す数は少ない方がいい。純粋に見やすくなる。
<ListGroup items={this.state.users} textProperty="name" valueProperty="id"/>
ListGroup
に渡すオブジェクトのほとんどがname
,id
プロパティを持っているとしよう。
こんな時はdefalut props
として親の方で明示しなくても、子がデータを受け取ることができる。
親コンポーネント
state = { users: [{ id: 1, name: 'rin' }, { id: 2, name: 'sin' }], languages: [{ number: 1, langName: 'JavaScript'}, { number: 2, langName: 'typeScript' }] } render () { <div className="container"> <ListGroup items={this.state.users} /> // 属性を渡さない <ListGroup items={this.state.languages} textProperty="langName" valueProperty="number"/> <div> }
子コンポーネント
const ListGroup = ({items, textProperty, valueProperty}) => { return ( <ul className="list-group"> {items.map(item =>( <li key={item[valueProperty]} className="list-group-item"> {item[textProperty]} </li> ))} </ul> ) } // 追加 // デフォルトでtextProperty = 'name'のように親からデータを受け取る ListGroup.defaultProps = { textProperty: 'name', valueProperty: 'id' }
【React】styled-componentsを使ってJavaScriptでCSSを書く
純粋なcssはエラーを吐かなかったり、クラス名を重複しないようにしたり、cssのためだけにクラス名をつけたり、と言ったデメリットが存在する。それを解決するstyled-components
を使っていく。
インストール
$ npm install styled-components
エディタにstyled-components用のプラグインを入れておくとよい。
プラグインがないとCSSに色がつかなくて見にくい。
基本
変数名 = styled.要素名
という文法で書く。
その変数はコンポーネントとして利用できる。コンポーネントは要素名で指定した要素になる。今回ならdiv
が生成される。
import styled from 'styled-components' const Main = () => { const Box = styled.div` background-color: aqua; width: 50%; height: 200px; ` return <Box /> } export default Main
sytled-componentsによってクラス名がつけられている
複数コンポーネント
import styled from 'styled-components' const Main = () => { const Box = styled.div` background-color: aqua; width: 50%; height: 200px; ` const BoxName = styled.h1` background-color: lime; ` return ( <Box> <BoxName> Hello React!</BoxName> </Box> ) } export default Main
引数を渡す
引数はコンポーネント作成時にprops
として受け取ることができる。${}
で変数展開をする。
直接${props.bgColor}
のように記述してもダメで、アロー関数の引数をprops
とする必要がある。`
import styled from 'styled-components' const Main = () => { const Box = styled.div` background-color: aqua; width: 50%; height: 200px; ` const BoxName = styled.h1` background-color: ${props => props.bgColor}; color: ${props => props.color ? props.color : 'black'}; ` return ( <Box> <BoxName bgColor="red" color="white"> Hello React!</BoxName> <BoxName bgColor="lime"> Hello JavaScript!</BoxName> </Box> ) } export default Main
ベースコンポーネントを継承する
例えば文字は基本的には赤色だが、場合によっては黒にしたい、フォントを太くしたい、といった時に役に立つ。HTML要素もベースとなるコンポーネントを継承する。例えばベースコンポーネントがdiv
なら継承して作成されたコンポーネントもdiv
である。継承のやり方はstyled(baseComponentName)
と書くだけ。
import styled from 'styled-components' const Main = () => { const Box = styled.div` background-color: aqua; width: 50%; height: 200px; ` const BoxName = styled.h1` color: orangered; text-align: center; ` // BoxNameコンポーネントを継承。h1タグとcssを継承する。 // cssは上書きすることができる。 const BoxNameWhite = styled(BoxName)` color: black; font-weight: bold; background-color: lime; ` return ( <Box> <BoxName> Hello React!</BoxName> <BoxNameWhite> Hello JavaScript!</BoxNameWhite> </Box> ) } export default Main
CSSをネストをさせる
ネストもSCSSのように非常に簡単にできる。
import styled from 'styled-components' const Main = () => { const Box = styled.div` h2 { color: green; :hover { text-decoration: underline; } } background-color: aqua; width: 50%; height: 200px; ` const BoxName = styled.h1` color: orangered; text-align: center; ` const BoxNameWhite = styled(BoxName)` color: black; font-weight: bold; background-color: lime; ` return ( <Box> <BoxName> Hello React!</BoxName> <BoxNameWhite> Hello JavaScript!</BoxNameWhite> <h2>Hello TypeScript!</h2> </Box> ) } export default Main
おしまい!Vueの楽しいけどReactも楽しい!
【JavaScript】アロー関数の引数で分割代入をする
Reactでよく使われるアロー関数の引数で分割代入を行うパターンを解説する。
まずは分割代入の復習から
分割代入はオブジェクトのキーと値をオブジェクトの外に出して変数として使えるようにすること。
英語名はObject destructuring
で、その名の通りオブジェクトを破壊して値を取り出す、といったイメージである。オブジェクトに存在しないキーを指定するとundefined
が格納される。
const person = { name: 'lamp', age: 22, isMan: true } console.log(name, age) // => Uncaught ReferenceError: Cannot access 'name' before initialization" const { name, age, adress } = person console.log(name, age, adress) // => "lamp", 22, undefined
別名をつけて分割代入
キー : 新しい名前
という文法で書く。
const person = { name: 'lamp', age: 22 } const { name: userName, age: userAge } = person console.log(userName, userAge) // => "lamp", 22 console.log(name, age) // => Uncaught ReferenceError: age is not defined"
アロー関数の引数で分割代入
呼び出すときは引数で代入しているプロパティをもったオブジェクトを渡す。
const person = { name: 'lamp', age: 22, isMan: true, money: 36, haveChild: true } const fn = ({ name, age, isMan, ...rest }) => { console.log(name, age, isMan); console.log(rest); } fn(person) // => "lamp", 22, true // => { haveChild: true, money: 36 }
見ての通り、可変調引数rest
には配列ではなくオブジェクトが格納されている。
【React】子コンポーネントから親コンポーネントへデータを渡す
子が好きなタイミングで親のメソッド実行する
Vueと同じように子コンポーネントの好きなタイミングで親コンポーネントに作成したカスタムイベントを発火させることができる。その時の引数としてデータを受け取る、という流れである。
注意点として、親コンポーネントではカスタムイベント={メソッド名}
として関数への参照を渡す。
子から送られてきたデータは引数としてメソッド内で受け取ることができる。
// 親コンポーネント handleMyEvent = (value) => { console.log(value) // 3 } <Counter myEvent={this.handleMyEvent} /> // 子コンポーネント <button onClick={() => this.props.myEvent(3)} >myEventを発火</button>
データフローは単一方向
データフローは単一方向、つまり「親から子へ」という一方通行である。 親のデータを子から変更することはできない。子のデータは親からもらうので、もちろん子は親のデータに依存している。 具体例で説明しよう。
親が貧乏になると一緒に子どもも一緒に貧乏になる。一方で、子どもが親からもらったお小遣いを使い果たしても親は貧乏にならない。子どもは親のお金を勝手に使うことはできない。じゃあどうするか?子どもは親に「お金が欲しい。いくら欲しい」ということを伝えるのだ。親は事前にお金がなくなったら言いなさい、と子どもにカスタムイベントを渡している。あとはそれを、子どもが引数つき(なくてもよい)で、好きなタイミングで実行するのだ。親は我が子の助けが来たらお金をあげようとずっと待ち構えている(イベントを購読)。親はそのイベントが起きるとまたお金をあげる、つまり任意の関数を実行するのである。
controlled component
controlled component
とは自分でstate
を持たないコンポーネントのことである。
props
で親から全てのデータを受け取り、データを変更したい時は親からもらったイベントを発火させる。
そして親のメソッド内でデータを変更する。
つまり、その名の通り完全に親に依存するコンポーネントである。
【Git 】git switchでリモートブランチをローカルに持ってくる
リモートブランチと同じ名前のブランチをローカルに持ってくる
新しいコマンドのgit switch
が便利!
$ git switch remote_branch_name
もしうまくいかない場合は$ git fetch
を実行してローカルのリモート追跡ブランチを更新してください。
リモートブランチと違う名前のブランチを作成する必要がある時
$ git checkout -b branch_name origin/branch_name
branch_name
は自分で命名できる。