React-pdf: Custom components not allowed in dynamic rendering

Created on 19 Nov 2018  路  11Comments  路  Source: diegomura/react-pdf


OS:
Mac OS 10.13.6

React-pdf version:
1.0.0-alpha.25

Description:
When trying to use my own custom components within a dynamic render, I get the following error:

Error: Invalid element of type <TYPE>
    at createInstance (/node_modules/@react-pdf/renderer/src/elements/index.js:30:9)
    at Page$1.createInstance [as addDynamicChild] (/node_modules/@react-pdf/renderer/src/elements/Page.js:114:26)
    at Page$1.addDynamicChild (/node_modules/@react-pdf/renderer/src/elements/Page.js:118:20)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

Looking at the source code, I see that only the basic components included with the library are whitelisted for use within dynamic rendering. I'm not sure what the constraints are there but it feels very limiting to not allow custom components, given the prevalence of this pattern in React.

How to replicate issue including code snippet (if applies):
Put any custom component inside a dynamic render function:

const MyCustomComponent = props => <Text>{props.children}</Text>;
const DynamicallyRenderedComponent = props => (
  <View
    render={({ pageNumber }) => (
      <MyCustomComponent>
         This will throw an error 
      </MyCustomComponent>
    )}
  />
);

_You can make use of react-pdf REPL to share the snippet_

enhancement

Most helpful comment

Unfortunately the way we are doing dynamic rendering right now does support that, it's true. That's because we have to create elements in render time and it's only possible to create primitives nodes.

@diegomura Any update on this? Would be an awesome feature. I'd love to help but don't completely understand the issue. Why is it only possible to create primitive nodes in render time? My custom component just renders a few primitives so there's something I'm missing here.

All 11 comments

I have the same question, how to add anything except text and images to the PDF? Like a table, normal HTML code etc.? If I want to create a nice report that the user can download as PDF..

These are different questions.

  • Custom components
    I just tried this and it worked for me. You should be able to create your own custom components that renders primitive components. The reason why some are white-listed in the source code has little to do. Custom components get's resolved by the react reconciler before getting to that phase. What you do there is just defining which are the leaf components that the renderer should support. Can you provide a small snippet/project to replicate that?

  • how to add anything except text and images to the PDF? Like a table, normal HTML code etc.?

React-pdf ships several primitives you can use to build a layout. If you want a table, you should build it using Views for example. You can wrap that up in a custom component if you like (or even publish it?. I've been wanting to do that fo awhile, but couldn't find time). A Table is not a primitive.

About normal HTML, that's not supported. That's because this is not an HTML-to-PDF solution, and you cannot just "add" HTML to a PDF. Some people are transforming their HTML into react-pdf primitives, and they say it worked well

I just tried this and it worked for me.

I get the same error using the REPL:

image

Here's the code snippet:

const MyCustomComponent = props => <Text>{props.children}</Text>;

const Example = () => (
  <Document>
    <Page>
      <View
        render={({ pageNumber }) => (
          <MyCustomComponent>
            This will throw an error
          </MyCustomComponent>
        )}
      />
    </Page>
  </Document>
);

ReactPDF.render(<Example />);

馃槗 sorry. I missed the fact that this was happening on dynamic render. My bad haha. I have too many things in my head.

Unfortunately the way we are doing dynamic rendering right now does support that, it's true. That's because we have to create elements in render time and it's only possible to create primitives nodes.

Maybe what we can do is running the reconciler only over that part of the tree, but not sure how it will work. I can't promise either when I'll be able to test it.

I understand that dynamic rendering may be handy for a bunch different scenarios, but it's very trick to set up for all of them. It was created mainly for page numbers and if statements, but not thinking of rendering custom components. Would be great to make it more powerful. If you like, you can give it a shot 馃槃 I'll be happy to assist you on the process

thank you for the great pdf toolkit, it worked really well for me to create selectable pdfs.

But so far i found one problem, similar to the one in this thread, trying to pass the pagenumber as a prop to my custom component to decide by the component how much content should be displayed until wrapped.

Issue: My content starts on the first page and not always wraps to the next page, additionally i have different fixed content starting on the second page until the end of the document, which is not shown on the wrap of the first page because the pages are handled separately.

Maybe you have another idea how to solve my issue, if it is somehow possible to get the page number in multipage documents to decide what will be printed on the page.
Alternative it would work for me to somehow pass the pages the fixed content should be rendered on / or not be rendered on, so i can put the whole document in one page and just disable the fixed content for the first page.

UPDATE: i think i found a way that works partly for me, with dynamic rendering inside my custom component i was able to solve that.

@Isarstyle do you mind sharing your solution for dynamic rendering inside custom components?

@gaithoben this is the return of my render method of the react class component that i put at the beginning of the , and is printed in the pdf starting on the second page until the end of the document.

<View fixed render={({ pageNumber }) => ( pageNumber > 1 && ( <View style={styles.header}> <Image style={styles.topLogo} src="../../images/logo.png" /> </View>

Thank you so much for your prompt reply. I thought you used a custom component for that.

https://react-pdf.org/advanced#dynamic-content
my issue here was that i tried to include the react component(my custom component) inside a dynamic rendered view in top level of the page element, and thats not possible. So to have reusable components for many different types of documents i had to use this workaround. Hopefully that helped you.

Thank you so much for the insight i struggled for almost a day.

Unfortunately the way we are doing dynamic rendering right now does support that, it's true. That's because we have to create elements in render time and it's only possible to create primitives nodes.

@diegomura Any update on this? Would be an awesome feature. I'd love to help but don't completely understand the issue. Why is it only possible to create primitive nodes in render time? My custom component just renders a few primitives so there's something I'm missing here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

saratonite picture saratonite  路  3Comments

emt1803 picture emt1803  路  3Comments

idrisadetunmbi picture idrisadetunmbi  路  3Comments

kishaningithub picture kishaningithub  路  4Comments

benbenedek picture benbenedek  路  3Comments