Help with setting up Portable Text in a React app
13 replies
Last updated: Oct 14, 2022
S
Is anyone willing to hold my hand and walk me through setting up the Portable Text? I have looked for as much information as I can on the matter but I can not seem to figure it out.
I have a basic schema set up:
And a mess of a .js file to render the content. (Upgrading from block content to html to portable text - therefore I am just trying to replace what we previously had)
I have a basic schema set up:
{ name: "text", title: "Text", type: 'array', of: [ { type: 'block' } ] },
import {toHTML} from '@portabletext/to-html' const BodyText = ({ text, layoutSettings } = {}) => { let className = 'body-text'; let ls = 'col-6'; if (layoutSettings?.sizing) { ls = layoutSettings.sizing; className = `${className} ${ls}`; } if (!text) { return `<p class="${className}"></p>`; } if (text.length > 1) { return blocks .map(block => block.children.map(child => child.text).join('')); } let bt = toHTML({ blocks: text }); bt = bt.replace(/<p/, `<p class="${className}" `); return bt; }; export default BodyText;
Oct 12, 2022, 9:49 PM
Could you please try commenting out the third if statement and block (text.length > 1) and removing the destructuring in the
let btline (so
let bt = toHTML(text))?
Oct 12, 2022, 10:13 PM
S
k, but that is removing the return statement that displays anything
Oct 12, 2022, 10:45 PM
S
so now I get nothing
Oct 12, 2022, 10:45 PM
S
Well, technically I get
<p class="body-text col-6"></p>
Oct 12, 2022, 10:47 PM
S
When those lines aren't commented I get this:Unknown block type "undefined", specify a component for it in the
components.typesoption
Oct 12, 2022, 10:48 PM
I see. I had tried implementing a pared down version of what you posted, so perhaps I misunderstood your code.
Where is
Where is
blockscoming from in this?
if (text.length > 1) { return blocks .map(block => block.children.map(child => child.text).join('')); }
Oct 12, 2022, 10:48 PM
S
So, that code is a bit of a mess becuase I was starting to replace the old code - and in doing so probably made mistakes. Here is the original code with the old blocks to html:
import blocksToHtml from '@sanity/block-content-to-html'; const BodyText = ({ text, layoutSettings } = {}) => { let className = 'body-text'; let ls = 'col-6'; if (layoutSettings?.sizing) { ls = layoutSettings.sizing; className = `${className} ${ls}`; } if (!text) { return `<p class="${className}"></p>`; } if (text.length > 1) { return blocksToHtml({ blocks: text, className: className, }); } let bt = blocksToHtml({ blocks: text }); bt = bt.replace(/<p/, `<p class="${className}" `); return bt; }; export default BodyText;
Oct 12, 2022, 10:51 PM
S
Oh, and I was looking at this info and copied and pasted that.. but looking at it now, I am realizing what I forgot. Regardless, I am still at a loss
Oct 12, 2022, 10:53 PM
I think the new @portabletext/to-html package will correctly handle whether there’s 1 or 1+ blocks (could be wrong, though), but if it doesn’t that should throw a different error.
[NB:
☝️This relates to whether or not you need
To go back to earlier, can you
[NB:
☝️This relates to whether or not you need
if (text.length > 1) {...}.]
To go back to earlier, can you
console.log(text)in your BodyText component? If it’s undefined, then your return makes sense, given:
if (!text) { return `<p class="${className}"></p>`; }
Oct 12, 2022, 10:57 PM
S
For some reason, nothing is showing up in the console no matter where i put the console.log and what I put in it
Oct 12, 2022, 11:04 PM
Hi Stevey. I just tested the following in a React app and it rendered the HTML. Hopefully it can be a starting point for your migration from the old package to the new one.
import {useEffect, useState} from 'react'; import {toHTML} from '@portabletext/to-html'; import configuredClient from './client'; export default function BodyText() { const [pt, setPt] = useState(); useEffect(() => { client.fetch(`*[_id == '92fae10c-3209-4b28-bedd-94df0df526c3'].body[]`) .then(res => setPt(res)) }, []) return pt && ( <div>{toHTML(pt)}</div> ) }
Oct 13, 2022, 1:49 AM
S
user A
Thank you so much for that, it definitely helped! I was out yesterday, so I didn't get a chance to mess with it until this morning. Here is the code that worked for me (in case anyone looks at this thread)import {toHTML} from '@portabletext/to-html'; const BodyText = ({ text, layoutSettings } = {}) => { let className = 'body-text'; let ls = 'col-6'; if (layoutSettings?.sizing) { ls = layoutSettings.sizing; className = `${className} ${ls}`; } if (!text) { return `<p class="${className}"></p>`; } if (text.length > 1) { return toHTML(text); } let bt = toHTML(text); bt = bt.replace(/<p/, `<p class="${className}" `); return bt; }; export default BodyText;
Oct 14, 2022, 2:18 PM
You’re welcome! Thank you for following up with your final code, which is admittedly more relevant to someone using that package than my React snippet. Glad you got this working; have a great weekend!
Oct 14, 2022, 2:20 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.