Integration
This guide covers common integration patterns for Annota.
Server Synchronization
Section titled “Server Synchronization”Auto-Save on Create
Section titled “Auto-Save on Create”function AutoSave() { const annotator = useAnnotator();
useEffect(() => { if (!annotator) return;
const handleCreate = async (annotation) => { await fetch("/api/annotations", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(annotation), }); };
annotator.on("createAnnotation", handleCreate); return () => annotator.off("createAnnotation", handleCreate); }, [annotator]);
return null;}Debounced Updates
Section titled “Debounced Updates”import { debounce } from "lodash";
function DebouncedSync() { const annotator = useAnnotator();
const saveUpdate = useMemo( () => debounce(async (annotation) => { await fetch(`/api/annotations/${annotation.id}`, { method: "PATCH", body: JSON.stringify(annotation), }); }, 500), [] );
useEffect(() => { if (!annotator) return; annotator.on("updateAnnotation", saveUpdate); return () => annotator.off("updateAnnotation", saveUpdate); }, [annotator, saveUpdate]);
return null;}Loading Annotations
Section titled “Loading Annotations”function LoadAnnotations({ slideId }) { const annotator = useAnnotator();
useEffect(() => { if (!annotator) return;
fetch(`/api/annotations/${slideId}`) .then((res) => res.json()) .then((annotations) => { annotator.addAnnotations(annotations); }); }, [annotator, slideId]);
return null;}State Management
Section titled “State Management”With Redux
Section titled “With Redux”function ReduxSync() { const annotator = useAnnotator(); const dispatch = useDispatch();
useEffect(() => { if (!annotator) return;
const handleChange = () => { dispatch(setAnnotations(annotator.getAnnotations())); };
annotator.on("createAnnotation", handleChange); annotator.on("updateAnnotation", handleChange); annotator.on("deleteAnnotation", handleChange);
return () => { annotator.off("createAnnotation", handleChange); annotator.off("updateAnnotation", handleChange); annotator.off("deleteAnnotation", handleChange); }; }, [annotator, dispatch]);
return null;}With Zustand
Section titled “With Zustand”function ZustandSync() { const annotator = useAnnotator(); const setAnnotations = useStore((s) => s.setAnnotations);
useEffect(() => { if (!annotator) return;
const sync = () => setAnnotations(annotator.getAnnotations());
annotator.on("createAnnotation", sync); annotator.on("updateAnnotation", sync); annotator.on("deleteAnnotation", sync);
return () => { annotator.off("createAnnotation", sync); annotator.off("updateAnnotation", sync); annotator.off("deleteAnnotation", sync); }; }, [annotator, setAnnotations]);
return null;}Image Sources
Section titled “Image Sources”<AnnotaViewer options={{ tileSources: "/path/to/image.dzi", }}/><AnnotaViewer options={{ tileSources: "https://server/iiif/image/info.json", }}/><AnnotaViewer options={{ tileSources: { type: "image", url: "/path/to/image.jpg", }, }}/>