rbenvによるバージョン切り替えの際の備忘録

2020/12/31 11:25


<p><a class="keyword" href="http://d.hatena.ne.jp/keyword/github">github</a>からforkしてきたプロジェクトの<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョン関連で問題が生じたので、経過とともにメモする。</p> <h4>経過&amp;メモ</h4> <ul> <li>forkしてきたプロジェクトの<code>.ruby-version</code>に書かれている<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョンを確認</li> <li><code>rbenv install x.x.x</code>で該当の<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョンを指定してインストール</li> <li>念の為<code>rbenv rehash</code>実行</li> </ul> <p>ここで、<code>rbenv rehash</code>をする意味を再度確認した</p> <blockquote><p>「~/.rbenv/versions/2.x.y/bin/ 以下に置いてあるコマンド群を ~/.rbenv/shims/以下に置いて使えるようにする」</p></blockquote> <p><a href="http://dqn.sakusakutto.jp/2014/02/rbenv_rehash_what_it_does.html">rbenv rehash&#x306F;&#x4F55;&#x3092;&#x3084;&#x3063;&#x3066;&#x3044;&#x308B;&#x306E;&#x304B;&#xFF1F; &middot; DQNEO&#x65E5;&#x8A18;</a></p> <ul> <li><code>bundle install</code>実行しようとしたら下記のエラーが表示されて出来ない</li> </ul> <pre class="code" data-lang="" data-unlink>Warning: the running version of Bundler (1.17.2) is older than the version that created the lockfile (1.17.3). We suggest you upgrade to the latest version of Bundler by running `gem install bundler`. Your Ruby version is 2.6.3, but your Gemfile specified 2.6.5</pre> <p>bundlerのバージョンが古いと言う警告と、<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョンが<code>.ruby-version</code>に書かれているものよりも古いというエラー。</p> <ul> <li>とりあえず、どこの<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>が呼ばれているか<code>which ruby</code>で確認 <ul> <li><code>/usr/bin/ruby</code>の方が呼ばれており、rbenvでインストールした<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>が呼ばれていないことを確認した <ul> <li>rbenvの方の<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>を呼び出したいので、下記の流れでpathを参照できるようにする</li> </ul> </li> </ul> </li> </ul> <pre class="code shell" data-lang="shell" data-unlink> ~$ vim ~/.bash_profile // .bash_profileが開かれるので、下記一行を追加して保存する export PATH=&#34;$HOME/.rbenv/shims:$PATH&#34; // 変更を反映させる ~$ source ~/.bash_profile </pre> <ul> <li>これで<code>bundle install</code>したところ正常にインストールできた</li> </ul> <h4>振り返り</h4> <p>前職に勤めていた時には、会社用のレポジトリは基本的に会社のPC上で触っていて、個人で何かする時には個人のPCでやっていたため<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョン切り替えをあまりやっていなかった。 今回、久方ぶりにforkしてきた<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%EA%A5%DD%A5%B8%A5%C8%A5%EA">リポジトリ</a>を動かす、ということをしたので<a class="keyword" href="http://d.hatena.ne.jp/keyword/ruby">ruby</a>のバージョン切り替え周りで少し手間取ってしまった。 rbenv、bundlerあたりはこういったケースをきちんとメモしておいてその都度理解を深めるのがいいかなと感じる。 実装周りが落ち着けば一度きちんと見たい。</p>

setStateで古いstateを見てしまった

2020/12/28 17:41


<p>基本的なところだけど、少し悩んでしまったのでメモ。</p> <p>アプリのタイマー機能を実装しようとした際、setIntervalを使用しても時間が加算されない問題が発生した。 原因としては、<b>setStateにオブジェクトを渡した場合、stateを即座にアップデートすることを保証しない</b>というもの。</p> <p><a href="https://ja.reactjs.org/docs/faq-state.html#how-do-i-update-state-with-values-that-depend-on-the-current-state">&#x30B3;&#x30F3;&#x30DD;&#x30FC;&#x30CD;&#x30F3;&#x30C8;&#x306E; state &ndash; React</a></p> <p>今回のような、setIntervalでsetStateが呼ばれるなど参照したいstateが絶えず更新されているものである場合、「setStateに更新用の関数を渡し、その関数内の引数で最新のstateにアクセスして操作する」のが正しい実装内容となる。</p> <h4>駄目な例</h4> <p>下記の例だと、<code>setState</code>にtimeに1を足した値を引数として渡しているが、この時にtimeが参照しているのは更新前のtimeである。 つまり、0秒から時間の加算が始まったとして、</p> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synComment">// timeは親のコンポーネントからもらってくる数値</span> <span class="synStatement">const</span> <span class="synIdentifier">[</span>time, setTime<span class="synIdentifier">]</span> = useState(props.time || <span class="synStatement">null</span>); useEffect(() =&gt; <span class="synIdentifier">{</span> <span class="synStatement">const</span> <span class="synIdentifier">{</span> taskId, recordingTaskId <span class="synIdentifier">}</span> = props; <span class="synStatement">if</span> (taskId &amp;&amp; taskId === recordingTaskId) <span class="synIdentifier">{</span> <span class="synComment">// setIntervalで時間加算の関数(addSecond)を1秒毎に実行させる</span> setTimerId(setInterval(addSecond, 1000)); <span class="synIdentifier">}</span> <span class="synStatement">else</span> <span class="synStatement">return</span>; <span class="synIdentifier">}</span>, <span class="synIdentifier">[</span>props.recordingTaskId<span class="synIdentifier">]</span>); <span class="synStatement">const</span> addSecond = () =&gt; <span class="synIdentifier">{</span> <span class="synComment">// ここでsetStateに「time + 1」という値を渡してしまっているため、常に古いstateを見てしまっている</span> setTime(time + 1); <span class="synIdentifier">}</span>; </pre> <h4>良い例</h4> <pre class="code lang-javascript" data-lang="javascript" data-unlink> <span class="synComment">// timeは親のコンポーネントからもらってくる数値</span> <span class="synStatement">const</span> <span class="synIdentifier">[</span>time, setTime<span class="synIdentifier">]</span> = useState(props.time || <span class="synStatement">null</span>); useEffect(() =&gt; <span class="synIdentifier">{</span> <span class="synStatement">const</span> <span class="synIdentifier">{</span> taskId, recordingTaskId <span class="synIdentifier">}</span> = props; <span class="synStatement">if</span> (taskId &amp;&amp; taskId === recordingTaskId) <span class="synIdentifier">{</span> <span class="synComment">// setIntervalで時間加算の関数(addSecond)を1秒毎に実行させる</span> setTimerId(setInterval(addSecond, 1000)); <span class="synIdentifier">}</span> <span class="synStatement">else</span> <span class="synStatement">return</span>; <span class="synIdentifier">}</span>, <span class="synIdentifier">[</span>props.recordingTaskId<span class="synIdentifier">]</span>); <span class="synStatement">const</span> addSecond = () =&gt; <span class="synIdentifier">{</span> <span class="synComment">// 更新関数を渡しているため、この中のtは最新のstateが入っていることが保証されている</span> setTime(t =&gt; t + 1); <span class="synIdentifier">}</span>; </pre>

親から子コンポーネントのstateにcreateRefを使ってアクセスする

2020/12/02 10:54


<p>表題の通りだけど、個人的におすすめしない。</p> <p>refでDOM要素にも<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>にも自由にアクセスできるようにはなるが、せっかくpropsで<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>間のやり取りができるようになっているので、あまりそれを崩したくない。 ちなみに、reactのリファレンスにはrefを使うのに適したケースとして以下が挙げられている。</p> <ul> <li>フォーカス、テキストの選択およびメディアの再生の管理</li> <li>アニメーションの発火</li> <li><a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B5%A1%BC%A5%C9%A5%D1%A1%BC%A5%C6%A5%A3">サードパーティ</a>の DOM ライブラリとの統合</li> </ul> <p><a href="https://ja.reactjs.org/docs/refs-and-the-dom.html">Ref &#x3068; DOM &ndash; React</a></p> <p>が、仕方ない場面はあるのでこういった方法を採用することもある。</p> <p>下記のようにして、子<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>のstateにアクセスできる。</p> <pre class="code lang-javascript" data-lang="javascript" data-unlink><span class="synComment">// クラスA内にBという子コンポーネントがあるとする</span> <span class="synStatement">class</span> A <span class="synStatement">extends</span> React.Component <span class="synIdentifier">{</span> constructor(props) <span class="synIdentifier">{</span> <span class="synStatement">super</span>(props); <span class="synComment">// stateを取得したい子コンポーネントにtestRefを渡すために、ここで作成</span> <span class="synIdentifier">this</span>.testRef = React.createRef(); <span class="synIdentifier">}</span> <span class="synComment">// クラスB内に作成したtestRefを渡す</span> &lt;B ref=<span class="synIdentifier">{this</span>.testRef<span class="synIdentifier">}</span> /&gt; <span class="synComment">// Bコンポーネント内の value というstateにアクセスできる</span> handleBstate = () =&gt; <span class="synIdentifier">{</span> <span class="synStatement">const</span> test = <span class="synIdentifier">this</span>.testRef.current.state.value <span class="synIdentifier">}</span> <span class="synIdentifier">}</span> </pre> <p>繰り返すが、あまりおすすめはしない。 瞬間的に子<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>の値を取得したい、関数を利用したいというケースでもなければあまり使わない方が無難だと思う。</p>