Skip to main content

Contexts

React Native Skia is using its own React renderer. It is currently impossible to automatically share a React context between two renderers. This means that a React Native context won't be available from your drawing directly. We recommend preparing the data needed for your drawing outside the <Canvas> element. However, if you need to use a React context within your drawing, you must re-inject it.

We found its-fine, also used by react-three-fiber, to provide an elegant solution to this problem.

Manual Context Injection

tsx
import React from "react";
import { Canvas, Fill } from "@shopify/react-native-skia";
import {useTheme, ThemeProvider} from "./docs/getting-started/Theme";
 
const MyDrawing = () => {
const { primary } = useTheme();
return <Fill color={primary} />;
};
 
export const Layer = () => {
const theme = useTheme();
return (
<Canvas style={{ flex: 1 }}>
{/* We need to re-inject the context provider here. */}
<ThemeProvider primary={theme.primary}>
<MyDrawing />
</ThemeProvider>
</Canvas>
);
};
 
export const App = () => {
return (
<ThemeProvider primary="red">
<Layer />
</ThemeProvider>
);
};
tsx
import React from "react";
import { Canvas, Fill } from "@shopify/react-native-skia";
import {useTheme, ThemeProvider} from "./docs/getting-started/Theme";
 
const MyDrawing = () => {
const { primary } = useTheme();
return <Fill color={primary} />;
};
 
export const Layer = () => {
const theme = useTheme();
return (
<Canvas style={{ flex: 1 }}>
{/* We need to re-inject the context provider here. */}
<ThemeProvider primary={theme.primary}>
<MyDrawing />
</ThemeProvider>
</Canvas>
);
};
 
export const App = () => {
return (
<ThemeProvider primary="red">
<Layer />
</ThemeProvider>
);
};

Using its-fine

tsx
import React from "react";
import { Canvas, Fill } from "@shopify/react-native-skia";
import {useTheme, ThemeProvider, ThemeContext} from "./docs/getting-started/Theme";
import { useContextBridge, FiberProvider } from "its-fine";
 
const MyDrawing = () => {
const { primary } = useTheme();
return <Fill color={primary} />;
};
 
export const Layer = () => {
const ContextBridge = useContextBridge();
return (
<Canvas style={{ flex: 1 }}>
<ContextBridge>
<Fill color="black" />
<MyDrawing />
</ContextBridge>
</Canvas>
);
};
 
export const App = () => {
return (
<FiberProvider>
<ThemeProvider primary="red">
<Layer />
</ThemeProvider>
</FiberProvider>
);
};
tsx
import React from "react";
import { Canvas, Fill } from "@shopify/react-native-skia";
import {useTheme, ThemeProvider, ThemeContext} from "./docs/getting-started/Theme";
import { useContextBridge, FiberProvider } from "its-fine";
 
const MyDrawing = () => {
const { primary } = useTheme();
return <Fill color={primary} />;
};
 
export const Layer = () => {
const ContextBridge = useContextBridge();
return (
<Canvas style={{ flex: 1 }}>
<ContextBridge>
<Fill color="black" />
<MyDrawing />
</ContextBridge>
</Canvas>
);
};
 
export const App = () => {
return (
<FiberProvider>
<ThemeProvider primary="red">
<Layer />
</ThemeProvider>
</FiberProvider>
);
};

Below is the context definition that was used in this example:

tsx
import type { ReactNode } from "react";
import React, { useContext, createContext } from "react";
 
interface Theme {
primary: string;
}
 
export const ThemeContext = createContext<Theme | null>(null);
 
export const ThemeProvider = ({
primary,
children,
}: {
primary: string;
children: ReactNode;
}) => (
<ThemeContext.Provider value={{ primary }}>
{children}
</ThemeContext.Provider>
);
 
export const useTheme = () => {
const theme = useContext(ThemeContext);
if (theme === null) {
throw new Error("Theme provider not found");
}
return theme;
};
tsx
import type { ReactNode } from "react";
import React, { useContext, createContext } from "react";
 
interface Theme {
primary: string;
}
 
export const ThemeContext = createContext<Theme | null>(null);
 
export const ThemeProvider = ({
primary,
children,
}: {
primary: string;
children: ReactNode;
}) => (
<ThemeContext.Provider value={{ primary }}>
{children}
</ThemeContext.Provider>
);
 
export const useTheme = () => {
const theme = useContext(ThemeContext);
if (theme === null) {
throw new Error("Theme provider not found");
}
return theme;
};