✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

Discussion on implementing code blocks in Portable Text with React Syntax Highlighter in Next.js

5 replies
Last updated: Jun 6, 2022
Good evening. I’ve hit a bit of a sticking point with portable text in Next.js and I’m wondering if anyone has attempted this here.
TLDR: I’m getting an error that reads
Error: code(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.

I came by this pull request that suggested a method to handle
<code>
in react.

https://github.com/portabletext/react-portabletext/pull/8/commits/46154520f029a429d30b4964ebcec91269581231
From there I looked into
npm
react-syntax-highlighter
as a nice way to serve up a code block in my project.

https://github.com/react-syntax-highlighter/react-syntax-highlighter
Having read the sanity docs on the topic

https://www.sanity.io/docs/presenting-block-text
I came up with an implementation that looks something like this…

JSON Data


"data": {
    "allPost": [
      {
        "contentRaw": [
           {
            "_key": "5978aa8a8ae9",
            "_type": "code",
            "code": "if (1 + 1 === 2) return 'Success'";
            "language": "javascript"
            },
         ]
      }
JS


...
<div className={utilStyles.postData}>
   <PortableText
      value={currPost[0].contentRaw}
      components={components}
   />

...
JS components

  const components = {
    types: {
      code: () => {
        contentRaw.forEach((block) => {
          if (block.hasOwnProperty('code')) {
            return (
              <SyntaxHighlighter language={block.language} style={nightOwl}>
                {block.code}
              </SyntaxHighlighter>
            );
          }
        });
      },
    },
  };

My expectation is that for each code type in the contentRaw JSON array (there are actually many), I should be returning out the styling from the component… instead I get the mentioned error
Error: code(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.

Might anyone be able to see where I have mis-stepped?
Jun 5, 2022, 10:20 PM
I am still in the learning phase myself, but in that last component area the thing that stuck out to me was the forEach and the return.
My first take is that if the return produces output for each iteration of foreach's internal function, the main
code: () =>
anonymous function doesn't have one of its own. If, instead, the return is for that anonymous function, then you'd only loop through one time before giving it a result, which undermines the loop.
You might not be using this exact tool but in the example here at this point in the page:
https://github.com/portabletext/react-portabletext#passing-a-components-prop they make it seem like the way it's set up is you're specifying a thing to happen any time a component type gets iterated over -- in other words, the looping is implicit.
If that's the case, and "code" is already the kind of "type" that "contentRaw"
is, it may be the case that you'd pass your props to the currently-anonymous function and proceed as normal from there.
Someone not-me will know better but my suspicion is that that's where the issue may lie.
Jun 6, 2022, 12:53 AM
I finally figured this out. On the off chance that it helps someone else in future, this is how I was able to configure the Portable Text component to render code blocks in React/Next.js using the React Syntax Highlighter…
You can ignore my above code and refer to the below for guidance.

I’m querying my database using GraphQL so my Portable Text component works with `contentRaw`… yours may be something else as GROQ may put the portable text content on a different property. With that said, this is how my
PortableText
component looks.

        <div className={utilStyles.postData}>
          <PortableText
            value={currPost[0].contentRaw}
            components={components}
          />
        </div>
From here you can follow the docs to install the
react-syntax-highlighter
package here
https://www.npmjs.com/package/react-syntax-highlighter
https://github.com/react-syntax-highlighter/react-syntax-highlighter
Once set up and imported appropriately, this is how I set up the
components
prop in
PortableText


  const components = {
    types: {
      code: (props) => (
        <SyntaxHighlighter
          language={props.value.language}
          style={nightOwl}
          wrapLongLines="true"
        >
          {props.value.code}
        </SyntaxHighlighter>
      ),
    },
  };
Notice the
wrapLongLines
prop. This allowed the
<code>
tag once rendered to wrap on small screens by adding the
style="white-space: pre=wrap"
prop. Other stylistic props from the
react-syntax=highlighter
docs can be added in this way.
Jun 6, 2022, 1:03 PM
Wonderful. It's good to know the solution follows the same spirit even if the information comes in differently. Also thank you for sharing; so often people arrive at something that others might want to know but they can't see what happened at the finish line to also benefit 😃
I haven't done code highlighting myself but the white-space threw me for a loop. I had to do insect/devtools to see that the white space was actually being carried over (I was trying to line up freely entered lists of hours and times for a business )
Jun 6, 2022, 2:16 PM
Glad you got this figured out, Akin. A key thing that was resolved by your newer code is that you’re no longer trying to return from a
forEach
callback.
Jun 6, 2022, 3:03 PM
Yes - 99% of the time, I avoid
forEach
, opting to go for a more suitable HO functions. In this case, I didn’t feel it was quite right but couldn’t see wood for trees by the time I asked the question 😅.
Jun 6, 2022, 4:16 PM

Sanity– build remarkable experiences at scale

Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?