react-pdf
react-pdf copied to clipboard
Support hooks in dynamic nodes
Hey there!
I'm working on a higher-level system on top of this library to bring document-wide theming, indexing (e.g. to generate table of contents) and much more. So far, everything works perfect in basic documents, but I run into issues when using the render
prop approach for dynamic nodes.
I get the infamous Invalid hook call.
and I guess it is due to the library not supporting hooks inside of render
props due to directly calling the render function or something. I find it a bit hard to navigate the source code to trim down the actual lines where this is resolved. I need hooks for config and theme context that my base level components use.
Consider this minimal reproduction:
import { createContext, useContext } from "react"
import { Page, Document, View, Text } from "@react-pdf/renderer"
const ThemeContext = createContext({})
function ThemedText({ children }) {
const theme = useContext(ThemeContext)
return <Text style={{ color: theme.colors.primary }}>{children}</Text>
}
function MyDocument() {
return (
<ThemeContext.Provider value={{ colors: { primary: "red" } }}>
<Document>
<Page>
<ThemedText>Works here</ThemedText>
<View
render={({ pageNumber }) => (
<ThemedText>Doesn't work here</ThemedText>
)}
/>
</Page>
</Document>
</ThemeContext.Provider>
)
}
For theme and config I could also use a singleton for now, but I also need context for inheritance in some components such as my custom Text. I get that most hooks such as useState
and useEffect
don't make sense in a static document, but context would actually be super useful due to sub-tree support e.g. having different themes and configs per subpage or something.
I'm more than happy to help if you guide me to the right direction! Would really add so much value for my library.
Oh, and I also tried to use Context.Consumer
instead of hooks just like we did before hooks shipped, but it also doesn't work properly. I think the issue lies somewhere in createInstances
, but I wasn't able to fix it myself for now.