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 Tips

Last updated at Posted at 2025-09-22

useState Tips

  • useStateの初期値は初回レンダリング時にのみ行われる。以降の更新では実行されない
  • 常に新しい値で演算
    conste handleClick = () => {
        setCount(c=>c+1);
        setCount(c=>c+1);
    };
    
  • (要確認)子コンポーネントで更新するとき、親コンポーネントからset関数を直接渡すのは避ける

オブジェクトを変更

例えば、配列[a,b,c,d] ※a,b,c,dはオブジェクト
という状態を管理してるとする
このとき、bを新しいオブジェクトに更新するときは

  1. 配列自体を新しく作る
  2. bを新しく作る。他のa,c,dは同じでOK
  3. 上記で作ったオブジェクトを設定する

ネストの深いプロパティを変更するときは、深いコピーが必要。スプレッド構文は浅いコピーなので注意。
なので、状態は極力フラットにする!かImmerライブラリを使う

NG
const [user, setUser] = useState({
  name: 'Alice',
  address: {
    city: 'Tokyo',
  },
});

function updateCity() {
  const newUser = { ...user }; // 浅いコピー
  newUser.address.city = 'Osaka'; // ネストされたオブジェクトを変更

  setUser(newUser); // userオブジェクトの参照は変わっていないため、再レンダリングされない!
}
OK
const [user, setUser] = useState({
  name: 'Alice',
  address: {
    city: 'Tokyo',
  },
});

function updateCity() {
  const newUser = {
    ...user, // userオブジェクトをコピー
    address: {
      ...user.address, // addressオブジェクトもコピー
      city: 'Osaka', // cityプロパティを更新
    },
  };

  setUser(newUser); // newUserオブジェクトは新しい参照を持つため、再レンダリングされる
}

useRef Tips

  • コアなイベント登録ができる
const btnRef = useRef(null);
useEffect(()=>{
const btn = btnRef.current;
btn.addEventListener('click',handleClick,{once:true});
return (()=>{
  // コンポーネント破棄時に明示的に除去する必要あり
  btn.removeEventListener('click',handleClick,{once:true});
})
},[])
return <button ref={btnRef}>ボタン</button>
  • Uncontrolled Inputに使える

useStateを使ったControlled Inputは入力するたびに再レンダリングが行われる。
入力フォーム自身はユーザがキーボードで入力するので、再レンダリングいらなくない?って時に使える。
バリデーションなど、リアルタイムに対応するのに不向き
デフォルト値はdefaultValueやdefaultCheckedを使う。valueやcheckedなどを使うと、固定されてしまう。

import {useRef} from 'react';
export default function Sample() {
    const name = useRef(null);
    const onClick = () => console.log(`Hello ${name.current.value}`);
    return (
        <form>
            <div>
                <input id="name" name="name" type="text" ref={name}/>
            </div>
        </form>
    )
}

ファイル入力ボックスは、再レンダリング不要なのでUncontrolled InputでOK

useId Tips

タグのidをハードコーディングするのは、重複する可能性があるので好ましくない

import {useId} from 'react';
export default function Sample() {
    const id = useId(); // コンポーネント毎のid
    return (<>
        <div id={`${id}-sample1`}>sample</div>
        <div id={`${id}-sample2`}>sample2</div>
    </>)
}

複数のReactアプリを動かすと、アプリ間で重複があるかもなのでプレフィックスをつける

// アプリAをid="root-a"の要素にマウント
const rootA = ReactDOM.createRoot(document.getElementById('root-a'),{identifierPrefix: 'root-a-'});
rootA.render(<AppA />);

// アプリBをid="root-b"の要素にマウント
const rootB = ReactDOM.createRoot(document.getElementById('root-b'), {identifierPrefix: 'root-b-'});
rootB.render(<AppB />);

再描画タイミング

  • State更新
  • 渡されたPropsの変更。渡されたコンポーネントがPropsを変更するのはご法度
  • 親コンポーネントの再描画

リストのキー

  • リストなどはkey属性がないと、Reactは配列の変更を検知できない
  • <></>ではキー設定できないので、<Fragment>を使う
  • indexはリストの追加削除ソートで変わるので、使わない。なければUUIDとか使うといいかも
  • key属性が必要となるのは、map呼び出しの中に現れる要素に対して。子コンポーネント内ではない

イベントオブジェクト

  • ReactでのイベントオブジェクトはJavascriptのそれではなく、ブラウザ間の仕様差を吸収したSyntheticEvent(合成イベント)
  • keyプロパティはイベント発生原因のキーを示す
    Ctrl押しっぱなしでqキーは「e.ctrlKey && e.key=="q"」で判定。「e.key == "Control" && e.key == "q"」ではない

その他

JSXの(return (...))は、Reactのレンダリングサイクルに従って毎回最新の値が使われます。
useEffectは「副作用の処理(例:状態の更新やAPI呼び出し)」に使うもので、
JSX内でuseStateの値を参照する場合は、常に最新の値が使われるため、
古い値が使われる心配はありません。
  • 副作用はイベントハンドラーに集約する。もしくはuseEffect
  • childrenはReact要素の配列なので、配列のメソッドが使える
  • reactのonChangeはjsのinputイベントと同じ。jsのchangeイベントはonBlurか直接addEventListenerする
0
0
0

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?