0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React・Vue 面倒くさい所

Last updated at Posted at 2025-03-21

React

useStateのクロージャー地獄

useStateは再描画ごとに呼び出される関数内で保持されてるstateと代入関数を返す関数ですが、返しているこの値は勝手に変わりません。
再描画によってコンポーネント関数が呼び出され、その中でuseStateが呼び出されて初めてその関数のクロージャー内でのみ更新されます。
クロージャー内で値が更新されても、その外の値は更新されません。
例えばこれです。

App.tsx
import { useState } from "react";

export const App = () => {
    const [count, setCount] = useState(0);
    function add(){
        setCount(count + 1);
        setTimeout(() => console.log(count), 1000);
    }
    return <div className="app">
        <button onClick={add}>{count}</button>
    </div>
}

setTimeoutを介すとクロージャーの外になるので、更新されず前の値がconsoleに出てきます。

対処法はあります。

代入関数の活用

TypeScriptだと変数の初期値がデフォルトになっていて面倒くさいです。
それに加え、取得するたびに再描画がされてしまいます。

let newCount = 0;
setCount(count => newCount = count);
console.log(newCount);

カスタムフック

このようにすると、上の色々を省略できます。
しかし上と同じく取得に再描画が必要です。

usestate.ts
import React from "react";

export const useState = <T>(defaultState: T) => {
    const [state, setState] = React.useState(defaultState);
    const getState = (): T => {
        let _state;
        setState(newState => _state = newState);
        return _state;
    }
    return [state, setState, getState];
}

App.tsx
import { useState } from "./usestate.js";

export const App = () => {
    const [count, setCount, getCount] = useState(0);
    function add(){
        setCount(count + 1);
        setTimeout(() => console.log(getCount()), 1000);
    }
    return <div className="app">
        <button onClick={add}>{count}</button>
    </div>
}

なぜかうまくいきませんでした。

useRefで再描画できればなあ

メモリ食いそう

下手したらクロージャーが大量に出来るのでメモリ食いそうです。

Vue

テンプレートでそのままグローバル変数を使えない

Vueで以下のようにグローバル変数を参照しようとすると、エラーが発生します。

App.vue
<script setup>
import { ref } from 'vue'

const msg = ref('Hello World!')
</script>

<template>
  <h1>{{ btoa(new Date().toString()) }}</h1>
  <input v-model="msg" />
</template>

この場合btoaがエラーの原因です。

対処法 変数を作る

このようにすれば一発で解決です。
コンポーネントのdataに保存されるためです。
しかしbindが必要で面倒くさいのと、Web APIを保存するのは無駄を感じます。

App.vue
<script setup>
import { ref } from 'vue'

const msg = ref('Hello World!')
const btoa = window.btoa.bind(window);
</script>

<template>
  <h1>{{ btoa(new Date().toString()) }}</h1>
  <input v-model="msg" />
</template>

結論

ReactのuseStateが返す値は勝手に変わらないので他クロージャーに値を渡すときなどに注意
Vueはテンプレートでそのまま使えないグローバル変数がある

個人としてはReactのようにJavaScriptに近いものが好きなのでReactにVueのプロキシベース変数を足してさいきょうのフレームワークが欲しい

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?