0
0

[React×Typescript] setStateした直後に更新後のstate変数を扱う方法

Posted at

はじめに

setStateとは?

React hooksの代表的な機能で、主にクラスコンポーネントにおいて用いられるメソッド。
Reactを使うなら useStatethis.setState()は避けれない(やってることは同じ..だと思う)

なぜこんなことを考えたのか

とあるコードにおいて新しい配列をstateに反映し、その直後に更新したstate変数の配列をいじるようなことになった。

以下がその例

//とあるクラスコンポーネント内


//選択したタスクアイテムを編集可能にしてフォーカスするためのメソッド
changeItemEditable(id:string){
    const items: CheckListItem[] = this.state.checklist.map((item:CheckListItem) => {
        return {
            id: item.id,
            name: item.name,
            isChecked: item.isChecked,
            isReadOnly: item.id === id?!item.isReadOnly:item.isReadOnly
        }
    })
    const target = document.getElementById(`text-input-id=${id}`);
    target?target.focus():undefined
    this.setState({checklist: items})
} 

//新しいタスクを追加するメソッド
addNewTask() { 
    const tasks = this.state.checklist
    const task = new Task(tasks);//タスクの追加・削除・検索などを管理するクラス
    const newTask = task.addTask()
    this.setState({checklist: [...tasks, newTask]});
    this.changeItemEditable(newTask.id);
}

このコードにおいて

  1. タスクを追加
  2. 空のタスクが追加され、編集するために追加後に自動フォーカス

を実現したかった。

しかしうまくいかなかった。

うまくいかなかった原因と解決策

うまくいかなかった原因

setStateは非同期関数だった
つまり上記の例でいくと先にthis.changeItemEditableが実行されていたのだ。
そのためchangeItemEditableメソッド内のsetState(更新前)の実行と、addNewTaskのsetState(更新)が同時に発火し、更新した直後に更新前に戻されるということが発生したのが原因だった。

解決策

setStateは非同期関数である
このことに着目すると答えは簡単でasync/awaitを使えばいい

以下が修正後のコード


changeItemEditable(id:string){
    const items: CheckListItem[] = this.state.checklist.map((item:CheckListItem) => {
        return {
            id: item.id,
            name: item.name,
            isChecked: item.isChecked,
            isReadOnly: item.id === id?!item.isReadOnly:item.isReadOnly
        }
    })
    const target = document.getElementById(`text-input-id=${id}`);
    target?target.focus():undefined
    this.setState({checklist: items})
} 
    

async addNewTask() { 
    const tasks = this.state.checklist
    const task = new Task(tasks);
    const newTask = task.addTask()
    await this.setState({checklist: [...tasks, newTask]});
    await this.changeItemEditable(newTask.id);
}

0
0
4

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