React18のTransitionを試す @yukilulu0229

## startTransition

https://ja.react.dev/reference/react/startTransition

startTransition を使うことで、UI をブロックせずに state を更新することができます。

### 使い方

```App.jsx
import React, {startTransition, useState} from 'react';
// import React, {useState, useTransition} from 'react';
import Avatar from "./Avatar.tsx";

type Task = {
  id: number;
  title: string;
  assignee: string;
}

const member:{} = {
  a: "A",
  b: "B",
  c: "C"
}

const generateDummyTasks = (): Task[] => {
  return Array(10000).fill(null).map((_, index) => {
    const addedIndex = index + 1;

    return {
      id: addedIndex,
      title: `task: ${addedIndex}`,
      assignee: addedIndex % 3 === 0 ? member.a : addedIndex % 2 === 0 ? member.b : member.c
    }
  });
}

const filteringAssignee = (assignee: string) => {
  if (assignee === "") return tasks;

  return tasks.filter((task) => task.assignee === assignee);
}

const tasks:Task[] = generateDummyTasks();

const Transition = () => {
  const [selectedAssignee, setSelectedAssign] = useState<string>("")
  const [taskList, setTaskList] = useState<Task[]>(tasks);

  const onClickAssign = (assignee: string) => {
    setSelectedAssign(assignee);
    // 重たい処理を分離する;
    startTransition(() => {
      setTaskList(filteringAssignee(assignee));
    })
  }

  return (
    <div>
      <h2>transition</h2>

      <div style={{display: "flex", justifyContent: "center"}}>
        <Avatar isSelected={selectedAssignee === member.a} onClick={onClickAssign}>{member.a}</Avatar>
        <Avatar isSelected={selectedAssignee === member.b} onClick={onClickAssign}>{member.b}</Avatar>
        <Avatar isSelected={selectedAssignee === member.c} onClick={onClickAssign}>{member.c}</Avatar>
      </div>

      <button onClick={() => onClickAssign("")}>リセット</button>

      {taskList.map((task) => (
        <div key={task.id} style={{width: "300px", margin: "auto", background: "lavender"}}>
          <p>タイトル: {task.title}</p>
          <p>担当: {task.assignee}</p>
        </div>
      ))}
    </div>
  );
};

export default Transition;

```

```
const onClickAssign = (assignee: string) => {
    setSelectedAssign(assignee);
    // 重たい処理を分離する;
    startTransition(() => {
      setTaskList(filteringAssignee(assignee));
    })
  }
```

重たい処理を分離する

## useTransition

https://ja.react.dev/reference/react/useTransition

useTransition は、UI をブロックせずに state を更新するための React フックです

### 使い方

```App.tsx
import React, {useState, useTransition} from 'react';
import Avatar from "./Avatar.tsx";

type Task = {
  id: number;
  title: string;
  assignee: string;
}

const member:{} = {
  a: "A",
  b: "B",
  c: "C"
}

const generateDummyTasks = (): Task[] => {
  return Array(10000).fill(null).map((_, index) => {
    const addedIndex = index + 1;

    return {
      id: addedIndex,
      title: `task: ${addedIndex}`,
      assignee: addedIndex % 3 === 0 ? member.a : addedIndex % 2 === 0 ? member.b : member.c
    }
  });
}

const filteringAssignee = (assignee: string) => {
  if (assignee === "") return tasks;

  return tasks.filter((task) => task.assignee === assignee);
}

const tasks:Task[] = generateDummyTasks();

const Transition = () => {
  const [selectedAssignee, setSelectedAssign] = useState<string>("")
  const [taskList, setTaskList] = useState<Task[]>(tasks);
  const [isPending, startTransition] = useTransition();

  const onClickAssign = (assignee: string) => {
    setSelectedAssign(assignee);
    // 重たい処理
    // setTaskList(filteringAssignee(assignee))

    // 重たい処理を分離する;
    startTransition(() => {
      setTaskList(filteringAssignee(assignee));
    })
  }

  return (
    <div>
      <h2>transition</h2>

      <div style={{display: "flex", justifyContent: "center"}}>
        <Avatar isSelected={selectedAssignee === member.a} onClick={onClickAssign}>{member.a}</Avatar>
        <Avatar isSelected={selectedAssignee === member.b} onClick={onClickAssign}>{member.b}</Avatar>
        <Avatar isSelected={selectedAssignee === member.c} onClick={onClickAssign}>{member.c}</Avatar>
      </div>

      <button onClick={() => onClickAssign("")}>リセット</button>

      {taskList.map((task) => (
        <div key={task.id} style={{width: "300px", margin: "auto", background: "lavender", opacity: isPending ? 0.5 : 1}}>
          <p>タイトル: {task.title}</p>
          <p>担当: {task.assignee}</p>
        </div>
      ))}
    </div>
  );
};

export default Transition;

```

```
const [isPending, startTransition] = useTransition();
```

宣言する

```
const onClickAssign = (assignee: string) => {
    setSelectedAssign(assignee);
    // 重たい処理を分離する;
    startTransition(() => {
      setTaskList(filteringAssignee(assignee));
    })
  }
```

重たい処理を分離する

```
<div key={task.id} style={{width: "300px", margin: "auto", background: "lavender", opacity: isPending ? 0.5 : 1}}>
```

pendingの状態でUIに変化を付けることができる


## useDeferredValue

コンポーネントが別れてるときとか?

https://ja.react.dev/reference/react/useDeferredValue

useDeferredValue は、UI の一部の更新を遅延させるための React フックです。

```TaskList.tsx

import React, {memo, useDeferredValue} from 'react';
import type {Task} from "./Transition.tsx";

type Props = {
  taskList: Task[];
}
const TaskList = memo(({taskList}: Props) => {
  const deferredTaskList = useDeferredValue(taskList)

  return (
    <>
      {deferredTaskList.map((task) => (
        <div key={task.id} style={{width: "300px", margin: "auto", background: "lavender"}}>
          <p>タイトル: {task.title}</p>
          <p>担当: {task.assignee}</p>
        </div>
      ))}
    </>
  );
});

export default TaskList;


```

```
 const deferredTaskList = useDeferredValue(taskList)
 ```

 useDeferredValueに入れる

 ```
 {deferredTaskList.map((task) => (
 ```

入れた変数で展開する

## 読み込み時間をわざと遅らせる関数

```App.tsx
const sleep = (ms: number):Promise<any> => {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  })
}

const fetchAlbums = async () => {
  const result = await axios.get<Album[]>("https://jsonplaceholder.typicode.com/albums").then(await sleep(5000));

  return result.data
}
```