fujjima’s blog

主に備忘録

近況について

こんにちは、fujjimaです。

ブログの方は、管理画面側は終わったんで一般画面の方作ってます。 全部Railsなので特殊なことは何もしてないです。月別アーカイブ作ってみて思ったけど、あれって結構実装面倒なんだね。

最近の近況だけ言うと、一応仕事はしています。 2ヶ月ぐらい前から仕事再開し出しました。まだ当分は今の現場で働きます。

今の現場では設計・実装は基本的に個人で進めつつも、適宜設計方針の議論などは活発に行なえている点がいいなと思います。 どのぐらいいるかは分からないけど、在籍している間は企業の成長に寄与できるように頑張っていきます。

Material-UIのSelect内のテキスト部分のスタイルをいじる

したいこと

Material-UIのSelectコンポーネント内にあるテキスト部分のスタイルを変更したかった。 具体的には、下図のようにテキストエリアの範囲を縮小したかった。

変更前

f:id:fujjima:20210208121616p:plain

変更後

f:id:fujjima:20210208121722p:plain

タグ構造

Select周りの構造は下記の通りになっているとする。 今回「ここから〜ここまで」で囲まれている範囲のスタイルを変更することを目的とした。 該当部分のReactコンポーネントも記載しているが、jsx用のシンタックスハイライトを当てていないので、雰囲気でおなしゃす。

<div class="MuiInputBase-root MuiOutlinedInput-root makeStyles-statusMenu-16">
  <!-- ここから -->
  <div
    class="MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input"
    tabindex="0"
    role="button"
    aria-haspopup="listbox"
    aria-labelledby="demo-simple-select-filled"
    id="demo-simple-select-filled"
  >
    未着手
  </div>
  <!-- ここまで -->
  <input
    aria-hidden="true"
    tabindex="-1"
    class="MuiSelect-nativeInput"
    value="waiting"
  /><svg
    class="MuiSvgIcon-root MuiSelect-icon MuiSelect-iconOutlined"
    focusable="false"
    viewBox="0 0 24 24"
    aria-hidden="true"
  >
    <path d="M7 10l5 5 5-5z"></path>
  </svg>
  <fieldset
    aria-hidden="true"
    class="PrivateNotchedOutline-root-29 MuiOutlinedInput-notchedOutline"
    style="padding-left: 8px"
  >
    <legend class="PrivateNotchedOutline-legend-30" style="width: 0.01px">
      <span><200b></span>
    </legend>
  </fieldset>
</div>
<Select
  id="demo-simple-select-filled"
  value={task.status}
  variant="outlined"
  className={classes.statusMenu}
>
  <MenuItem value="waiting">未着手</MenuItem>
  <MenuItem value="working">作業中</MenuItem>
  <MenuItem value="completed">完了</MenuItem>
  <MenuItem value="pending">保留</MenuItem>
</Select>

方法

MenuItemのinput部分のMuiOutlinedInput-inputに対してスタイルを設定する

statusMenu: {
  '& .MuiOutlinedInput-input': {
    paddingBottom: '7px',
      paddingTop: '7px',
    },
},

JSのbind、及び`this`について理解を少し深める

bindそのものについて

JSのbindの用法を知り、「どういう時に使われるのか」が漠然とイメージできるようになりたかったため、概要と使われ方を調べた。

とりあえず以下のサイトのデモコードを自分なりにいじってどういう挙動なのかは調べた。

Function.prototype.bind() - JavaScript | MDN

const module = {
  a: 50,
  b: 30,
  text: 'this is test',
  showText: function(){
    return this.text;
  },
};

const moduleShow  = module.showText;
console.log(moduleShow);

// moduleから抜き出した関数にmodule自体をbindする
// moduleShow内のthis = bindされたmoduleとなる
// そのため、this.text = module.text、になる
const boundGetX = moduleShow.bind(module);
console.log(boundGetX());


その他、bindの概要、callとの違いについては下記の記事を見てイメージは出来た。 JavaScript thisの内容を指定する(bindメソッド) | ITSakura

ただ、こいつがどういう目的で使われるかは分からなかった。*1

単純に、関数内のthis(thisがない場合はbind内の第一引数にnullを指定する)を特定のものに設定する(=undefinedにしない)場合にbindを使う、という使い方でいいのだろうか。

アロー関数内でのthisの扱われ方とbindの比較

ここまで調べて、そういえばJSの通常関数とアロー関数ではthisの指すものが異なる、という話しを思い出した。

【JavaScript】アロー関数式を学ぶついでにthisも復習する話 - Qiita

JavaScript: 通常の関数とアロー関数の違いは「書き方だけ」ではない。異なる性質が10個ほどある。 - Qiita


両者のthisに関する違いとしては、アロー関数はthisを束縛し、通常関数はthisを束縛しない(=関数呼び出し元(レシーバ)をthisとする)という点である。

下記のコードを例に比較する。

  • 通常関数
this.name = "globalName";

// 通常関数
function showName() {
  console.log(this.name);
}

let arrowFunc = {
  name: "john",
  func: showName,
};

arrowFunc.func();
=> john

// bindを使った場合
showName.bind(arrowFunc)();
=> john

arrowFunc.func()の返り値がjohnとなっており、これはarrowFunc.nameの値であることが分かる。 このことから、arrowFunc.func()、つまりはarrowFunc.showName()のshowName内部のthisはarrowFunc(レシーバ)を指していたことが分かる。

  • アロー関数
this.name = "globalName";

// アロー関数
const showName = () => {
  console.log(this.name);
};

let arrowFunc = {
  name: "john",
  func: showName,
};

arrowFunc.func();
=> globalName

arrowFunc.func()の返り値が「globalName」となっている。これは最初に定義したthis.name = "globalName"のnameの値が表示されていることが分かる。 ここで、アロー関数内のthisについてのリファレンスを見てみる。

アロー関数自身は this を持ちません。レキシカルスコープの this 値を使います。つまり、アロー関数内の this 値は通常の変数検索ルールに従います。このためスコープに this 値がない場合、その一つ外側のスコープで this 値を探します。

アロー関数 - JavaScript | MDN


アロー関数であるshowNameが定義された際、関数内のthisは更に外側のthisを見ていたことになる。 今回Node上で上記コードを実行したため、thisとして定義されていたのは{name: "globalName"}だったため、showName関数内のconsole.logで表示されたthis.nameは、コードの最初に定義したthis.nameだった、ということになる。


ちなみにトップレベル、グローバルスコープあたりはここを参考にした。

JavaScriptのトップレベルスコープは常にグローバルスコープではなかった - Qiita

まとめ

改めてbind、通常関数とアロー関数それぞれでのthisの使い方を確認した。 通常関数とアロー関数の違いについては他にも色々あるが、一旦知りたいと思っていたことを確認することができた。

*1:こういったサンプルを見て、「じゃあこういうものにも応用できるな」と考えつく能力もプログラマに必要不可欠な能力だよな、と最近感じている

需要が薄いMaterial-UIのvalidationの一例

空文字を許容しない、というバリデーションを一部分だけ書きたい、しかしそのために本格的なバリデーションの機構を組むのはめんどくさくて死にそう、という時にその場しのぎで書いたもの。

<TextField
  label="名前"
  variant="outlined"
  margin="normal"
  required

  // input.valueに入力された文字が入っているものとして、空文字の場合は input.value はfalseを返す
  // 上記の場合に{ error: true }を返すことで <TextField error /> と書いた時と同じようになる
  // { error: false } の場合はerrorは指定されていない状態になる
  {...(!input.value ? { error: true } : { error: false })}
/>

Material-UIのTextFieldをtype="date"にした際のdefaultValueに指定する日付のフォーマットについて備忘録

material-uiのTextFiledというAPIの中で、type="date"のようにタイプを指定することでDate pickerのように使用することができる。

Date picker, Time picker React components - Material-UI

その際、デフォルトの日付をdefaultValueというオプションで設定できるが、この部分で少し詰まったので備忘録として残す。

ダメだった例

// 年、月、日の区切りがスラッシュになっているとdefaultValueとして認識されない
const today = dayjs().format('YYYY/MM/DD')

<TextField
  label="testDay"
  type="date"
  defaultValue={today}
  margin="normal"
/>

f:id:fujjima:20210101144435p:plain

良かった例

// 年、月、日の区切りがハイフンだときちんとdefaultValueとして指定できる
const today = dayjs().format('YYYY-MM-DD')

<TextField
  label="testDay"
  type="date"
  defaultValue={today}
  margin="normal"
/>

f:id:fujjima:20210101144333p:plain

詳細は調査中だが、同じようにdatapickerとして使用できるKeyboardDatePickerではformatにformat="MM/dd/yyyy"のように指定してもいける感じなので、どうしてこのような仕様にしているかはよく分からない。 しかも表示される時にはYYYY/MM/DD形式だし。スラッシュどこに行った。

https://material-ui.com/components/pickers/#material-ui-pickers