UNPKG

react-native-filament

Version:

A real-time physically based 3D rendering engine for React Native

86 lines (82 loc) 2.67 kB
import React, { createContext, useCallback, useContext, useEffect, useMemo } from 'react'; import { useSharedValue } from 'react-native-worklets-core'; /** * In react-native-filament we can only have one render callback, which we provide to the FilamentView. * This context allows us to have multiple render callbacks, as we call them in the render callback. */ export const makeRenderContext = () => { const RenderContext = /*#__PURE__*/createContext({ renderCallbacks: { value: [], addListener: () => { throw new Error('RenderContextProvider not found'); } }, addRenderCallback: () => { throw new Error('RenderContextProvider not found'); } }); const RenderContextProvider = ({ children }) => { const renderCallbacks = useSharedValue([]); const addRenderCallback = useCallback(callback => { const id = Math.random().toString(36).substring(7); const entry = { callback, id }; renderCallbacks.value.push(entry); return () => { renderCallbacks.value = renderCallbacks.value.filter(e => e.id !== id); }; }, [renderCallbacks]); const contextValue = useMemo(() => ({ renderCallbacks, addRenderCallback }), [addRenderCallback, renderCallbacks]); return /*#__PURE__*/React.createElement(RenderContext.Provider, { value: contextValue }, children); }; const useRenderContext = () => { const context = useContext(RenderContext); if (!context) { throw new Error('useRenderContext must be used within a RenderContextProvider'); } return context; }; /** * Use this method to add render callbacks to the render callback chain. */ const useRenderCallback = (callback, deps) => { const { addRenderCallback } = useRenderContext(); useEffect(() => { const remove = addRenderCallback(callback); return () => { remove(); }; // Explicitly skip the callback, we memoize by the provided dependencies // eslint-disable-next-line react-hooks/exhaustive-deps }, [...deps, addRenderCallback]); return callback; }; /** * This should be called in the render callback of the FilamentView. * For the default exported context this happens automatically. */ const useRenderCallbacks = () => { const renderContext = useRenderContext(); return renderContext.renderCallbacks; }; return { useRenderContext, RenderContextProvider, useRenderCallback, useRenderCallbacks }; }; export const RenderCallbackContext = makeRenderContext(); //# sourceMappingURL=RenderCallbackContext.js.map