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
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
コンポーネントが別れてるときとか?
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
}