Type-checking lazily loaded components
Answered
Giant panda posted this in #help-forum
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:
In its implementation, I'm using
<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 truthy12 Replies
@Giant panda 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:
mdx
<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?
you shouldn't touch
instead, do something like
children.instead, do something like
function Explanation({ children }) {
if (shouldHide) return null;
return <div>{children}</div>;
}@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:
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
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.
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.
@joulev i wouldn't do that. instead
tsx
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.
Giant pandaOP
I'd love to use props, but MDX doesn't parse markdown after you've escaped into js. Are there no alternatives?
particularly the
mdx templateit'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 truthyAnswer
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.