VSCodeでGoを書いてgit pushするとインデントがおかしくなる時の対処法
次のお仕事でGolangを使うのでGoを勉強中です。しかし困ったことがありました。
起こったこと
- VSCodeでGoを書く
- 保存してgit pushする
- Git Hub上でコードをみる
- 何じゃこのアホみたいなインデント!!
原因
VSCodeの拡張機能、Goが保存時にインデントをスペースからタブへ変更していた。
そのタブはVSCode上の見た目では分からない。(Tabは→、Spaceは・で見ることはできるけど)
Githubではタブは8スペースで表示される。
対策
その1 Goの拡張機能をOffにする
極めて微妙。せっかくの拡張機能がなくなってしまう。
↓の記事にgo.formatOnSave
をfalse
にすればいけるよ、って書いてあるけどsetting.json
に書いても動かなかった。
でも普通に保存時のコード整形は欲しい。
その2 諦める
Goではインデントにタブ(4スペース前提)を使うことが推奨されている。だから強引にスペースにするのがそもそも間違っていた。 素直にフォーマッターに従うべきだ。
その3 Git HubのTabスペースを変更する
クエリパラメーターで?ts=2
とか?ts=4
とすると見た目を変更できる。だが毎回こんなことできるわけがない。
Chromeの拡張機能を見つけた。これを使うか〜
Githubのタブが8文字で見にくいのでextensionで解決 - Qiita
【React】Hooksを使って関数コンポーネントに状態を持たせる
昔の話
昔は関数コンポーネントとクラスコンポーネントは明確に違った。
関数コンポーネント
- 状態を持たない
- ライフサイクルメソッド(
componentDidMount
など)使えない
クラスコンポーネント
- 状態を持つ
- ライフサイクルメソッドが使える
このような違いあった。しかしHooksが導入されてから、関数コンポーネントでもクラスコンポーネントと同じことができるようになった。
なぜHooksが導入されたのか
クラスコンポーネントは難しいから
ベテランエンジニアにとっては慣れているかもしれないが、クラス構文は駆け出しエンジニアには理解しづらい。またJavaScriptのクラスはRubyのようなオブジェクト指向言語のクラスとは違う。JavaScriptのクラスはコンストラクター関数の糖衣構文にすぎないのだ。
コードの記述量を減らすため
クラスコンポーネントには決まり文句のようなコードが多い。そして、その量が無駄に多いのである。しかしHooksを使うとコードの記述量を減らすことができる。
Hooksを使ってみる
import React, { useState, useEffect } from 'react' function Counter(props) { // useStateの引数には初期値を渡す // 初期値(state)と値を更新する関数を変数に代入 const [count, setCount] = useState(0) const [name, setName] = useState('') // componentDidMount // componentDidUpdateと同じ役割 // つまり、コンポーネントがレンダリングされる度に呼ばれる useEffect(() => { document.title = `${name}が${count}回クリックしました!` // componentWillUnmountはここに書く return () => console.log('お掃除しました!') }) return ( <> <input type="text" onChange={e => setName(e.target.value)}/> <p>{name}が{count}回クリックしました!</p> <button onClick={() => setCount(count + 1)}>増やす</button> </> ) } export default Counter
useEffectは再利用ができる
useEffect()
をラップした新しい関数を作成して別ファイルに切り出す。その関数をimport
すれば異なるコンポーネント間での再利用が可能になる。これもHooksを使う大きなメリットになりそう。
【React】高階コンポーネントを使ってみる
高階コンポーネントって何?
高階コンポーネントは高階関数と似ている。高階関数とは関数を戻り値とする関数のこと。
高階コンポーネントは引数でコンポーネントを受け取り、戻り値として新しいコンポーネントを返す関数のこと。
どんな時に使うの?
クラスの継承と似ていると思う。親クラスに状態(state
)やメソッドを定義して、子クラスで使い回す。似たような処理を機能を持つコンポーネントを複数個作成する時に使える。
サンプルコード
ルートのコンポーネント:App.js
import Movie from './hoc/Movie' function App() { return ( <Movie id={1}/> ) } export default App
高階コンポーネント:withTooltip.js
(withから名前をつけるのが慣例)
引数で受け取るコンポーネントの親になる。
import React from 'react' function withTooltip(Component) { return class withTooltip extends React.Component { state = { showTooltip: false} mouseOver = () => this.setState({ showTooltip: true }) mouseOut = () => this.setState({ showTooltip: false }) render() { return ( <div> <p>マウスを乗せると答えが出るよ</p> <Component onMouseOver={this.mouseOver} onMouseOut={this.mouseOut} showTooltip={this.state.showTooltip} {...this.props} // 親からもらったデータを全て渡す /> </div> ) } } } export default withTooltip
最下層の子コンポーネント: Movie.js
import React, { Component } from 'react' import withTooltip from './withTooltip' class Movie extends Component { render() { return ( <div> <span>id: {this.props.id}</span> <p onMouseOver={this.props.onMouseOver} onMouseOut={this.props.onMouseOut} > 高級コンポーネントとは? </p> {this.props.showTooltip && <p>コンポーネントを返す関数だよ</p>} </div> ) } } export default withTooltip(Movie) // 戻り値はWithTooltipにラップされたMovieコンポーネント // つまりMovieコンポーネントを子に持つWithTooltipコンポーネントである
親子関係はこの通り。Appで渡したidもしっかりとMovieへ渡すことができている。
【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
には配列ではなくオブジェクトが格納されている。