Gene documentation
Services
Fetch on demand

Implementing On-Demand Data Fetching and Updates with Service Hooks

Service hooks provide a consistent API across all services. However, some situations require on-demand data retrieval, such as when a user interacts with an element. For these cases, the useMyServiceLazy hook can be used. This hook, automatically created with a Lazy suffix when a service is generated, is designed for executing data fetching and mutations as needed. It also provides methods for updating the UI immediately and keeping data in sync after changes.

Reactive Operations with useMyServiceLazy

The useMyServiceLazy hook is especially useful in scenarios where data fetching and updates are triggered by user actions, such as button clicks.

Example of Fetching Data On-Demand

const { fetch, data, loading, error } = useMyServiceLazy();
 
const handleClick = (variables) => {
  fetch(variables).then((data) => {
    // Do something with data
  });
};
 
if (loading) {
  return 'loading';
}
 
if (error) {
  return error;
}

Strategies for Data Synchronization

  • Optimistic Updates: Provide a simulated response (optimisticResponse) for immediate visual feedback in the UI, assuming the mutation will succeed.
  • Manual Cache Updates (updates): Directly modify the cache after a mutation using the provided update functions.
  • Automated Query Refetching (refetchQueries): Specify which queries to rerun after a successful mutation for automatic data sync.

Practical Examples

Modifying an Existing TODO Item

import { queryKey as getTodoListQueryKey } from '@acme/services/get-todos-service';
import { useEditTodoLazy } from '@acme/services/update-todo-service';
 
const { fetch: updateTodo } = useEditTodoLazy();
 
function updateTodoItem(todoId, updatedDetails) {
  updateTodo({
    variables: { id: todoId, ...updatedDetails },
    optimisticResponse: {
      // Construct the optimistic UI update here...
      ...updatedDetails,
    },
    updates: [
      {
        queryKey: getTodoListQueryKey({ userId }),
        updateFn: (existingTodos, updatedTodo) => ({
          ...existingTodos,
          todos: existingTodos.todos.map((todo) =>
            todo.id === todoId ? { ...todo, ...updatedTodo } : todo
          ),
        }),
      },
    ],
    refetchQueries: [
      // Alternatively, refetch the query for automatic updates
      getTodoListQueryKey({ userId }),
    ],
  });
}

Adding a New TODO Item

import { queryKey as getTodoListQueryKey } from '@acme/services/get-todos-service';
import { useAddTodoLazy } from '@acme/services/add-todo-service';
 
const { fetch: addTodo } = useAddTodoLazy();
 
function addNewTodoItem(todoDetails) {
  addTodo({
    variables: { ...todoDetails },
    optimisticResponse: {
      id: 'temp-id', // Temporary ID until backend confirmation
      ...todoDetails,
    },
    updates: [
      {
        queryKey: getTodoListQueryKey(),
        updateFn: (existingTodos, newTodo) => ({
          ...existingTodos,
          todos: [...existingTodos.todos, newTodo],
        }),
      },
    ],
    refetchQueries: [
      // Alternatively, refetch the query for automatic updates
      getTodoListQueryKey({ userId }),
    ],
  });
}

These examples demonstrate the use of optimistic updates for seamless user interaction and two methods for updating the cache: manual updates via updates and automatic synchronization using refetchQueries. This flexibility allows developers to handle various mutation scenarios effectively, ensuring a reliable and responsive application state.