Next.js Discord

Discord Forum

Type-checking lazily loaded components

Answered
Giant panda posted this in #help-forum
Open in Discord
Giant pandaOP
Hey everyone, I've come across an interesting pattern that I'd like to use. I have the following Question component that uses children elements to retrieve data rather than accepting its own props:

<Question>
  <Prompt>
    The HTML code below uses incorrect syntax. What could you do to fix it?

    <CodeSnippet>
      \`\`\`html
       <p>I'm a paragraph<p>
      \`\`\`
    </CodeSnippet>  
  </Prompt>

  <Option>Remove the `p` within each pair of angled brackets</Option>
  <Option>Add a `/` before the `p` in the closing tag</Option>
  <Option>None of these options would work</Option>

  <Explanation>
    Remember that an **opening tag** demarcates the start of an element's inner 
    content (i.e. text) and the **closing tag** indicates the end thereof. A slash (`/`) 
    is needed to differentiate between an opening tag and a closing tag.
  </Explanation>
</Question>


In its implementation, I'm using children.find(c => c.type === Option), for instance, to retrieve data and then render the component appropriately, but this doesn't seem to work with the MDX output, since it looks like the type is "react.lazy" instead of the function of my component. Does anyone know how to get children by type when they are lazily loaded like so?
Answered by joulev
you could probably wrap the children of Question inside a react context containing the value of explanationShown, then in the Explanation component, read that context and only render the children if explanationShown is truthy
View full answer

12 Replies

@joulev you shouldn't touch `children`. instead, do something like tsx function Explanation({ children }) { if (shouldHide) return null; return <div>{children}</div>; }
Giant pandaOP
How would you work around having to place children at different points in the tree?
e.g:
@Giant panda How would you work around having to place children at different points in the tree? e.g:
i wouldn't do that. instead

function Question({ prompt, options, explanation }) {
  return ...
}

<Question
  prompt={<div>...</div>}
  options={
    <>
      <Option ... />
      <Option ... />
      <Option ... />
    </>
  }
  explanation={<div>...</div>}
/>


in vue/svelte/etc., the pattern you are trying to use is called "slots". in react we don't have slots, the closest we can get is this.
particularly the mdx template
it's not too easy. but the rule still holds: do not touch children, so you have to find alternatives
@joulev it's not too easy. but the rule still holds: do not touch `children`, so you have to find alternatives
Giant pandaOP
Do you think making an assumption about the order of the children and then getting the first and last children as the prompt & explanation respectively would be an acceptable exception to that rule?
to be fair, if it works, it works. if you can make it work, then why not. but such solutions are doomed to be hacky and spaghetti-y, not recommended
@Giant panda How would you work around having to place children at different points in the tree? e.g:
you could probably wrap the children of Question inside a react context containing the value of explanationShown, then in the Explanation component, read that context and only render the children if explanationShown is truthy
Answer
you should be careful though, you could accidentally send explanation to the client even when it should not be shown, then a hacker student could probably manage to uncover it to read the solution. lots of footguns here, be careful
@joulev you should be careful though, you could accidentally send `explanation` to the client even when it should not be shown, then a hacker student could probably manage to uncover it to read the solution. lots of footguns here, be careful
Giant pandaOP
Question itself is a client component, so the explanation would already be shipped to the client ahead of time. These aren't quizzes with the purpose of a certification, but rather simple as-you-go questions to boost retention. I do very much agree with your aforementioned solution though. Thanks for the help.