とーますメモ

Ruby on Rails / Goなどの学習メモ

【Next.js】Apollo Queryの返り値を元に、新しいデータを非同期で取得する場合

ちょっとハマったので、自分のメモ用。

以下のissueにかかれていたことを元にして解決。
github.com

上記の内容をカスタムフックにラップすればOK

const { loading, data, error } = useQuery(SOME_QUERY)
const [state, setState] = React.useState([])

React.useEffect(() => {
  // do some checking here to ensure data exist
  if (data) {
    // mutate data if you need to
    setState(data)
  }
}, [data])

年月のみを入力した場合、その月の最終日を自動補完する方法

年月のみが入力されたときも、当月の最終日を自動補完するコードを作った。

ex) A1に年月または年月日が入力される前提

TEXT(IF(LEN(A1)=7, EOMONTH(A1, 0), C2:C), "YYMMDD")

2022/06 => 220630
2022/06/20 => 220620

ポイントはLEN関数の長さが7の場合で、年月判定している箇所。
他にも年月判定する方法があるかもしれないが、これでとりあえずは対応できる。

※ EOMONTHの第2引数を0にすると当月の最終日が取得できる

TypeScriptで簡易Sprintfを作成する

Validationメッセージなどのメッセージには決まった文言が入るが、一部を置き換えたい場合などは、テンプレートリテラルよりC言語系で使われるSprintfが便利なのだが、JavaScriptにないため自作した。

export const sprintf = (format: string, ...args: string[]): string => {
  return format.replace(/{(\d+)}/g, (_match, index) => {
    return args[index];
  });
};

sprintf('{0}を入力してください', '名前')
=> '名前を入力してください'

[参考]
javascript - Convert JS sprintf to Typescript equivalent - Stack Overflow
Is there a sprintf equivalent for node.js - Code Examples

React Hook Form v7 × Material UIを使用したときのメモ書き

React Hook Formを使用するのは初めて。
React Hook Formを使用することでform内の値を管理するstateが不要になり、バリデーション機能も含まれているため、コード量を大幅に減らすことができる。またネット上にサンプルも非常に多いのも魅力的。

form値の監視や、他のUIライブラリとも組み合わせるのも可能。

React Hook Form ファーストインプレッション

v7について

React Hook Formはv7では書き方が以前のバージョンとは違っている。
ちなみに公式の説明はこちら
Migrate From V6 to V7 | React Hook Form - Simple React forms validation

register関数の使い方
- <input ref={register({ required: true })} name="test" />
+ <input {...register('test', { required: true })} />

スプレッド構文を使用することでシンプルに記述できるようになった。
以下が影響が大きそうな部分。

Controller
- <Controller as={<input />} />
+ <Controller render={({ field }) => <input {...field} />}

- <Controller render={(props, meta) => <input {...props} />} />
+ <Controller render={({ field, fieldState }) => <input {...field} />} />

as属性は廃止になり、代わりにrender属性をv7からは使用する。
render属性はfieldとfieldStateを含むオブジェクトを返す。

errros
- const { errors } = useForm();
+ const { formState: { errors } } = useForm();

errorsオブジェクトはfromStateオブジェクト内に属することになった。

実装時に困ったこと

Select要素のラベル表示にすごく困った。
React Hook FormとMaterial UIを併せたSelectのサンプルを紹介しているサイトは結構あるけど、v7のやり方でやってる例が意外となく、Material UIのform独特なかっこいいラベルのUIが、うまく動作しないという問題が発生した。

結論から言うと、以下のサイトさんを参考にし
React 初心者が Material-UI で今どきの Web フォームを作ってみた(react-hook-form編) | DevelopersIO

Controller内にTextFieldを入れて、Textfieldにselect属性をつけることで
Material UIのあのかっこいいUI効果があるラベルが実装できた。

<Controller
  name="sample_select"
  control={control}
  defaultValue={"default value"}
  render={({ field }): JSX.Element => (
    <TextField {...field} fullWidth size="small" select label={"Sample Select"}>
      {options.map((v) => (
        <MenuItem key={v.name} value={v.id}>
          {v.name}
        </MenuItem>
      ))}
    </TextField>
  )}
/>


[参考]
Using Material UI with React Hook Form - LogRocket Blog

【React】Material UIについてのメモ書き

Material UI学習時のメモ書き

Gridシステム

bootstrapを使用するときも同じだが、まずは基本のGridシステムの使い方を最初に知る必要がある。

Gridは親Gridでcontainerを書き、その内側の子Gridでitemを定義する。
boostrapでいう、div class='container'とdiv class='row'と同じ関係。

<Grid container spacing={2}>>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
</Grid>

レスポンシブデザインは、boostrapと同じように、breakpointがあり内容は以下。

xs, extra-small: 0px
sm, small: 600px
md, medium: 900px
lg, large: 1200px
xl, extra-large: 1536px

Breakpoints - Material UI
モバイルベースのxsベースで考えて、必要に応じてmdやlgを使う。

Auto-layoutという機能もあり、12の数値を全て、各rowに割り振るのではなく、
その一部に当てはめればあとは、使用可能ならスペースに応じて、均等に割り振ったwidthでレイアウトしてくれる。

<Grid container spacing={3}>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>xs=6</Item>
  </Grid>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
</Grid>

Grid container(親Grid)でよく使用する属性

direction

子Gridの並び順を定義できる。rowで横並び、columnで縦並び

<Grid container direction="row">
justifyContent

親Gridをメイン軸とし、子Gridを横軸のどの位置に配置するかを指定する
【CSS】justify-content使い方、アイテムの配置する位置を指定する | SHU BLOG

<Grid container justifyContent="flex-start"> // 先頭寄せ
<Grid container justifyContent="center"> // 中央寄せ
<Grid container justifyContent="flex-end"> // 末尾寄せ
alignItems

親Gridをメイン軸とし、子Gridを縦軸のどの位置に配置するかを指定する
【CSS】align-itemsの使い方、配置する方向を指定する! | SHU BLOG

<Grid container alignItems="flex-start"> // 上部寄せ
<Grid container alignItems="center"> // 中央寄せ
<Grid container alignItems="flex-end"> // 下部寄せ
spacing

子Grid間のスペースを設定できる。小数点を含めた正の数を指定できる。
またv5からspacingを含めた全てのproprsでレスポンシブ値をサポート

<Grid container spacing={{ xs: 2, md: 3 }} />
rowSpacingとcolumnSpacing

rowSpacing(縦)とcolumnSpacing(横)の間隔をサポート

<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
columns

デフォルトのカラム数である12を変更することができる。
細かいレイアウト表現が必要な時に便利そう。

<Grid container spacing={2} columns={16}>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
</Grid>

sxを使ったスタイルの当て方

こんにちはMUI! 新しくなったMaterial UI v5

追記

V5でできるようになったこと。

こんにちはMUI! 新しくなったMaterial UI v5

TypeScript 4.5 ファーストインプレッション

個人用メモ。解釈が正しいかは不明なので参考までに。

TypeScript4.5がリリースされたので、その内容を簡単に試してみる。
devblogs.microsoft.com

TypeScriptを既にインストールしている場合は、以下で最新版に更新。

$ npm update typescript

初めてインストールする場合は以下。

$ npm install typescript

公式によるとTypeScript4.5の主な追加項目は以下。

The Awaited Type and Promise Improvements

The Awaited type can be helpful for modeling existing APIs, including JavaScript built-ins like Promise.all, Promise.race, etc. In fact, some of the problems around inference with Promise.all served as motivations for Awaited.

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#awaited-type

よくわからん。何が便利になるのかも不明。

=> PromiseLikeの説明
thenが実装しているPromise風オブジェクトのこと?

const fakePromise = { then: () => string };

async/await がやっていること - Qiita
JavaScriptの非同期処理をじっくり理解する (2) Promise

Supporting lib from node_modules

TypeScript does bundle certain libraries to ensure it works together well with Javascript. However, you might want to change those to another type of library implementation.

It is a similar behavior as of @types where you can now choose your appropriate type definitions.

https://betterprogramming.pub/whats-new-in-typescript-4-5-57d6b88b1e72

TypeScriptにバンドルされているライブラリの型定義ファイルを
指定することができるようになるため、適切な型定義ファイルを使用できるようになる?みたい。

TypeScript 4.5 変更点 まとめ

Template String Types as Discriminants

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#template-string-discriminants

以下のような、テンプレートリテラルの使い方ができるようになった。4.4以下では失敗する。

export interface Success {
    type: `${string}Success`;
    body: string;
}

export interface Error {
    type: `${string}Error`;
    message: string;
}

export function handler(r: Success | Error) {
    if (r.type === "HttpSuccess") {
        // 'r' has type 'Success'
        let token = r.body;
    }
}

--module es2022

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#module-es2022

TypeScriptでes2022モジュールをサポートできるようになった。
一番重要だと思われる機能は、awaitをasync関数外でも使用できるようになること。

Tail-Recursion Elimination on Conditional Types

Conditional Typesで型レベル末尾再帰最適化を行うらしい。

TypeScript 4.5 変更点 まとめ

よくわからん。飛ばす...

Disabling Import Elision

特定の条件下の元で、importしたモジュールを使用している場合、TypeScriptはそのモジュールを未定義と判断し削除するのを防ぐオプション。

以下のようなケースが想定される。

import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");

Announcing TypeScript 4.5 - TypeScript

import { readFile } from "node:fs/promises";
eval(`readFile("./package.json", "utf-8").then(console.log);`);

TypeScript 4.5 変更点 まとめ

type Modifiers on Import Names

今まではtype修飾子をimport文で使用するときは、モジュールのimportととは分けて記述する必要があったが、4.5からは一緒にかけるようになった。

import type { FC } from 'react';
import { useEffect } from 'react';
import { type FC, useEffect } from 'react';

Private Field Presence Checks

プライベートプロパティの存在チェック。ユースケースがよくわからないが、
このチェックを使用することで、あるインスタンスが、どのクラスから生成されたかを証明することができるようになるということだと思う。
TypeScript 4.5 変更点 まとめ

Import Assertions

ランタイム実行時に、インポートする対象が想定したフォーマットになっているかチェックすることができる。この機能は、どうやらJSONなどのコードを実行する機能がないファイルをインポートする場合は、明示的にフォーマットを指定させることでセキュリティを向上させる狙いがあるっぽい。
GitHub - tc39/proposal-import-assertions: Proposal for syntax to import ES modules with assertions

Const Assertions and Default Type Arguments in JSDoc

一例として、as constを使用せずにJSDocのアサーションを使用することで同じ表現が可能になった?的なことかと。

Faster Load Time with realPathSync.native

内部的な話っぽいので、スキップ。

New Snippet Completions

補完機能が強化された模様。読む限り良さげな改善内容。
新しいVSCode上で動作するとのことだが、自分の環境では確認できず...

Better Editor Support for Unresolved Types

特定のケースにおいて、関数名をマウスオーバー時に表示されるコンテキスト情報が改善された模様。

Experimental Nightly-Only ECMAScript Module Support in Node.js

実験的な機能についての言及。よくわからない。


[参考資料]
TypeScript 4.5 変更点 まとめ
What’s New in TypeScript 4.5?. Awaited Type, type-only modifier… | by Jose Granja | Nov, 2021 | Better Programming

【Ruby】[2021版] MacでRailsが突然動かなくなった話

以前やらかしたことを、またやらかしてしまったので、
再度動作できるようにするまでのメモ。
thoames.hatenadiary.jp

TL;DR

opensslが1.1系に書き換わってる可能性大!!!!
なので以下のことをすれば直った。
1) openssl1.0をインストール
2) /usr/local/opt/opensslのシンボリックリンクを1)でインストールしたパスに貼る。
3) brew switch openssl1.0のパスを直接していする。

経緯

原因は恐らく今度もXcode関係かbrew関係のコマンドを弄ったかが原因だと思われる。
Railsを起動しようとしたら、以下のエラーが出たため
他のサイトに書いてあるとおりに、一度消して再インストールするという同じ過ちを犯してしまった。

$ bundle exec rails s

...
LoadError - library not found for class Digest::SHA1 -- digest/sha1
...

今後は、Rails関係でサーバが立ち上がらないときは、必ず自分のメモを見るように肝に命じておきたい...

自分の場合は/usr/local/opt/opensslのシンボリックリンクが、openssl@1.1を向いていたので
これを古いバージョン(以前使用していたのは1.0.2q)へ向け直す必要があったので、brew switchと組み合わせて以下のようなコマンドで、なんとか2.3.1がインストールできた。

ちなみに古いバージョンのopensslは「/usr/local/Cellar/openssl」に入っている。

$ brew switch openssl 1.0.2q
$ RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/opt/openssl" rbenv install 2.3.1
$ rbenv rehash
$ rbenv global 2.3.1
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin18]

以前は上記での対応で良かったが、今回はなんと
「/usr/local/opt/openssl」のシンボリックリンクもなくなっており、
旧バージョンの「/usr/local/Cellar/openssl」もきれいに無くなっていた。
おいぃいいいい!!!どうなってる!!!!!!

以下のことをやったら直ったのでメモ

Openssl1.0のインストール

1.0系がきれいに消えているので再インストール

$ brew install rbenv/tap/openssl@1.0

インストールすると、「/usr/local/Cellar/openssl@1.0/1.0.2t」にインストールされる。

シンボリックの向きを1.0に向ける。

opensslのシンボリックリンクが消えていたので、1.0に向けて貼り直す。

$ cd /usr/local/opt
$ ln -s ../Cellar/openssl@1.0/1.0.2t openssl

brew switchコマンドで、openssl1.0に向きを変える

$ brew switch openssl /usr/local/Cellar/openssl@1.0/1.0.2t

あとは、前の記事と同じようにRuby, bundler, mysqlをインストールし直した。
これで動作した。

[参考]
brew upgradeしたらopensslが1.1.1gになってしまいRailsが起動できなくなってしまったとき - Qiita