baptiste0928
baptiste0928
SSolidJS
Created by baptiste0928 on 7/29/2023 in #support
How to avoid rerenders when using refetch ?
Hi, I'm trying to build a simple todo list app using Solid. Everything has been fine so far, I really enjoy using Solid! When I decided to add CSS transitions when adding an item to the todo list, I noticed that all items in the list were re-rendered each time they were added. After some investigation, I found that this re-rendering was caused by refetch, which when called causes a re-rendering of the entire list. Using mutate works as expected, so I suspect that the reactivity is lost because the list is replaced with a whole new object. What's the best way to avoid this kind of re-renders?
// api.ts

const [todos, { mutate, refetch }] = createResource(fetchTodos)

async function fetchTodos(): Promise<Todo[]> {
const api = useApi()
return await api<Todo[]>('/user/todos')
}

export async function createTodo(
todo: { title: string; description: string; dueTime: Date },
): Promise<Todo> {
// ... (constructing request)

const createdTodo = await api<Todo>(
'/todos',
{ method: 'POST', body: requestBody },
)

mutate(todos => [...todos ?? [], createdTodo])
refetch() // <- this call causes the re-render

return createdTodo
}

export { todos as userTodos }
// api.ts

const [todos, { mutate, refetch }] = createResource(fetchTodos)

async function fetchTodos(): Promise<Todo[]> {
const api = useApi()
return await api<Todo[]>('/user/todos')
}

export async function createTodo(
todo: { title: string; description: string; dueTime: Date },
): Promise<Todo> {
// ... (constructing request)

const createdTodo = await api<Todo>(
'/todos',
{ method: 'POST', body: requestBody },
)

mutate(todos => [...todos ?? [], createdTodo])
refetch() // <- this call causes the re-render

return createdTodo
}

export { todos as userTodos }
// TodoList.tsx

// ...

const TodoListPart: Component<{ name: string; status: TodoStatus }> = (props) => {
const filteredTodos = () => userTodos()?.filter(todo => todo.status === props.status) ?? []

return (
<div class="mt-8">
<h2 class="text-lg font-bold">{props.name}</h2>
<For each={filteredTodos()} fallback={<EmptyPart />}>
{todo => <TodoItem title={todo.title} status={todo.status} />}
</For>
</div>
)
}

const TodosList: Component = () => {
return (
<Suspense fallback={<Loading />}>
<TodoListPart name="Not started" status={TodoStatus.NOT_STARTED} />
<TodoListPart name="Todo" status={TodoStatus.TODO} />
<TodoListPart name="In progress" status={TodoStatus.IN_PROGRESS} />
<TodoListPart name="Done" status={TodoStatus.DONE} />
</Suspense>
)
}

export default TodosList
// TodoList.tsx

// ...

const TodoListPart: Component<{ name: string; status: TodoStatus }> = (props) => {
const filteredTodos = () => userTodos()?.filter(todo => todo.status === props.status) ?? []

return (
<div class="mt-8">
<h2 class="text-lg font-bold">{props.name}</h2>
<For each={filteredTodos()} fallback={<EmptyPart />}>
{todo => <TodoItem title={todo.title} status={todo.status} />}
</For>
</div>
)
}

const TodosList: Component = () => {
return (
<Suspense fallback={<Loading />}>
<TodoListPart name="Not started" status={TodoStatus.NOT_STARTED} />
<TodoListPart name="Todo" status={TodoStatus.TODO} />
<TodoListPart name="In progress" status={TodoStatus.IN_PROGRESS} />
<TodoListPart name="Done" status={TodoStatus.DONE} />
</Suspense>
)
}

export default TodosList
8 replies