Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
apollo-offline-hooks
Advanced tools
A drop-in replacement for @apollo/react-hooks with automatic cache updates. It will update apollo cache based on a mutation or subscription result.
npm i apollo-offline-hooks @apollo/react-hooks --save
or
yarn add apollo-offline-hooks @apollo/react-hooks
import React from 'react';
import {render} from 'react-dom';
import ApolloClient from 'apollo-boost';
import {ApolloProvider} from 'apollo-offline-hooks';
const client = new ApolloClient({
uri: 'localhost:8080',
});
const App = () => (
<ApolloProvider client={client}>
<div>
<h2>My first Apollo app 🚀</h2>
</div>
</ApolloProvider>
);
render(<App />, document.getElementById('root'));
This package extends useMutation options allowing to update cached queries in one line of code instead of writing complex update
functions.
For example this code
import React from 'react';
import {useMutation, useQuery} from 'apollo-offline-hooks';
import {createTodoMutation, todosQuery} from './api/operations';
import {TodosList} from './TodosList';
export const Todos = () => {
const {data} = useQuery(todosQuery);
const todos = data?.todos || [];
const [createTodo] = useMutation(createTodoMutation, {
updateQuery: todosQuery // <== pass a gql query you want to update
});
const handleCreateTodo = () => {
return createTodo({
variables: {
task: 'New todo',
createdAt: new Date().toISOString()
}
});
};
return (
<div>
<button onClick={handleCreateTodo}>Create todo</button>
<TodosList todos={todos} />
</div>
);
};
is equivalent to
import React from 'react';
import {useMutation, useQuery} from '@apollo/react-hooks';
import {createTodoMutation, todosQuery} from './api/operations';
import {TodosList} from './TodosList';
export const Todos = () => {
const {data} = useQuery(todosQuery);
const todos = data?.todos || [];
const [createTodo] = useMutation(createTodoMutation);
const handleCreateTodo = () => {
return createTodo({
variables: {
task: 'New todo',
createdAt: new Date().toISOString()
},
update: (proxy, {data}) => {
const newTodo = data.createTodo;
try {
const cache = proxy.readQuery({query: todosQuery});
proxy.writeQuery({
query: todosQuery,
data: {
todos: [...cache.todos, newTodo]
}
});
} catch (error) {
console.log(error)
}
}
});
};
return (
<div>
<button onClick={handleCreateTodo}>Create todo</button>
<TodosList todos={todos} />
</div>
);
};
And this code
import React from 'react';
import {useMutation} from 'apollo-offline-hooks';
import {Todo} from './api/generated';
import {deleteTodoMutation, todosQuery, updateTodoMutation} from './api/operations';
type Props = {
todo: Todo;
};
export const Todo: React.FC<Props> = ({todo}) => {
const [deleteTodo] = useMutation(deleteTodoMutation, {
updateQuery: todosQuery,
// to delete an item we need to provide it's id
// if our api simply returns true when item is deleted
// we need to return an id explicitly
mapResultToUpdate: data => todo
});
const [updateTodo] = useMutation(updateTodoMutation);
const handleDeleteTodo = () => {
return deleteTodo({
variables: {id: todo.id}
});
};
const handleUpdateTodo = () => {
return updateTodo({
variables: {id: todo.id, done: !todo.done}
});
};
return (
<li>
<input type="checkbox" checked={todo.done} onChange={handleUpdateTodo} />
{todo.task}
<button onClick={handleDeleteTodo}>delete</button>
</li>
);
};
is equivalent to
import React from 'react';
import {useMutation} from '@apollo/react-hooks';
import {Todo} from './api/generated';
import {deleteTodoMutation, todosQuery, updateTodoMutation} from './api/operations';
type Props = {
todo: Todo;
};
export const Todo: React.FC<Props> = ({todo}) => {
const [deleteTodo] = useMutation(deleteTodoMutation);
const [updateTodo] = useMutation(updateTodoMutation);
const handleDeleteTodo = () => {
return deleteTodo({
variables: {id: todo.id},
update: proxy => {
try {
const cache = proxy.readQuery({query: todosQuery});
proxy.writeQuery({
query: todosQuery,
data: {
todos: cache.todos.filter(item => item.id !== todo.id)
}
});
} catch (error) {
console.log(error)
}
}
});
};
const handleUpdateTodo = () => {
// apollo client is clever enough to update an item in cache
// although if you want to update an item with different type you'll have to write
// a manual update function
return updateTodo({
variables: {id: todo.id, done: !todo.done}
});
};
return (
<li>
<input type="checkbox" checked={todo.done} onClick={handleUpdateTodo} />
{todo.task}
<button onClick={handleDeleteTodo}>delete</button>
</li>
);
};
useMutation
offline optionsOption | Description | Default |
---|---|---|
updateQuery | A graphql query (wrapped in gql tag) that should be updated. You can pass query directly or specify it with variables {query: todosQuery, variables: {limit: 10}} | |
idField | Unique field that is used to find the item in cache. It should be present in the mutation response | id |
operationType | Indicates what type of the operation should be performed e.g. add/remove/update item. By default operation type is automatically detected from mutation name e.g. createTodo will result in OperationTypes.ADD . | OperationTypes.AUTO |
mapResultToUpdate | A function that receives mutation result and returns an updated item. Function result should contain at least an id field |
Other useMutation
hook options
Offline options can be passed to the useMutation
hook or to the mutation function directly.
const [deleteTodo] = useMutation(deleteTodoMutation, {
updateQuery: todosQuery,
mapResultToUpdate: data => todo
});
const handleDeleteTodo = () => {
return deleteTodo({
variables: {id: todo.id}
});
};
is the same as
const [deleteTodo] = useMutation(deleteTodoMutation);
const handleDeleteTodo = () => {
return deleteTodo({
variables: {id: todo.id},
updateQuery: todosQuery,
mapResultToUpdate: data => todo
});
};
useSubscription
accepts the same offline options as useMutation
useSubscription(onTodoUpdate, {updateQuery: todosQuery});
Other useSubscription
hook options
Default configurations can be customized by calling setOfflineConfig
import {setOfflineConfig} from 'apollo-offline-hooks';
setOfflineConfig({
getIdFieldFromObject(item: any) {
switch (item.__typename) {
case 'Todo':
return 'id';
case 'User':
return 'user_id'
}
}
});
Option | Description | Default |
---|---|---|
idField | Unique field that is used to find the item in cache. It should be present in the mutation response | id |
getIdFieldFromObject | A function that receives updated item and returns an id field name. If defined it will tke precedence over idField | |
prefixesForRemove | A list of mutation name prefixes that will result in remove operation | prefixesForRemove |
prefixesForUpdate | A list of mutation name prefixes that will result in update operation | prefixesForUpdate |
prefixesForAdd | A list of mutation name prefixes that will result in add operation | prefixesForAdd |
This package also exposes updateApolloCache
function directly, that can be used to build custom implementations
Example
import {updateApolloCache} from 'apollo-offline-hooks';
const newTodo = {
__typename: 'Todo',
id: 1,
task: 'New todo',
done: false,
createdAt: new Date().toISOString()
};
updateApolloCache({
client,
data: {createTodo: newTodo},
updateQuery: todosQuery
});
Function signature
type OfflineOptions<TData> = {
updateQuery?: QueryWithVariables | DocumentNode;
idField?: string;
operationType?: OperationTypes;
mapResultToUpdate?(data: NonNullable<TData>): Item;
};
type UpdateCacheOptions<TData = any> = OfflineOptions<TData> & {
client: ApolloClient<any> | DataProxy;
data: TData;
};
const updateApolloCache: <TData = any>({
client,
data,
idField,
updateQuery,
operationType,
mapResultToUpdate
}: UpdateCacheOptions<TData>) => void;
This package is based on Amplify Offline Helpers
FAQs
Apollo React Hooks with automatic cache updates
The npm package apollo-offline-hooks receives a total of 15 weekly downloads. As such, apollo-offline-hooks popularity was classified as not popular.
We found that apollo-offline-hooks demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.