Votemike
Votemike

Reputation: 882

How can I build HTML gradually in React?

I am trying to build some HTML in the following format:

<h1>Title</h1>
<p>
  Always existing sentence. Optional sentence.<br/>
  Always existing sentence. Optional sentence.
</p>
<p>
  <span>Always existing span</span>
  <span>Optional span</span>
</p>

What is the best way to construct/render this? The nearest I have got is some JSX:

const title = <h1>Title</h1>
const line1 = [`Always existing sentence.`];
const line2 = [`Always existing sentence.`];

if (condition) {
  line1.push(`Optional sentence.`);
  line2.push(`Optional sentence.`);
}
const para1 = React.createElement('p', null, [line1.join(' '), line2.join(' ')].join('<br/>'));

const spans = [React.createElement('span', null, `Always existing span`)];
if (condition2) {
  spans.push(React.createElement('span', null, `Optional span`));
}

const para2 = React.createElement('p', null, spans.join('<br/>'));

return <>{title}{para1}{para2}</>;

This works apart from the final paragraph which renders as <p>[object Object]<br/>[object Object]</p>. I assume because the spans are ReactElements. But I don't know how to join() them. Or even if this is the best approach.
So, what is the best way to gradually build up HTML to render in React?

Upvotes: 1

Views: 115

Answers (2)

Votemike
Votemike

Reputation: 882

I ended up doing the following in order to achieve what I set out to:

const title = <h1>Title</h1>
const line1 = [`Always existing sentence.`];
const line2 = [`Always existing sentence.`];

if (condition) {
  line1.push(`Optional sentence.`);
  line2.push(`Optional sentence.`);
}
const para1 = <p>{line1.join(' ')}<br/>{line2.join(' ')}</p>;

//This is a huge span
const span1 = <span>Always existing span.</span>;
let span2 = null;
if (condition2) {
  //This is a huge span
  span2 = <span>Optional span.</span>;
}

const para2 = <p>{span1}{span2 && (<><br/>{span2}</>)}</p>;

return <>{title}{para1}{para2}</>;

Still seems a bit unclean, but it works and it was the best I could come up with.

Upvotes: 0

Nick
Nick

Reputation: 1422

I believe what you're looking for is conditional rendering of JSX. You have the right idea with your pseudocode, you just need to change that if (condition) into checking for the value of a state variable. It's unclear if you're using the class syntax or hooks, so I'll provide an example using hooks for simplicity. The same idea applies regardless of which syntax you use.

Whenever state changes in React, the component will be re-rendered. With showOptionalContent set to false by default, the optional content will not be displayed. When showOptionalContent is changed to true, the component will re-render and the optional content will be displayed. You can use lifecycle methods or the useEffect hook to call a method that changes the state depending on when/why you want the optional content to be rendered.

const [showOptionalContent, setShowOptionalContent] = setState(false);

return (
    <div>
        <h1>Title</h1>
        <div>Always rendered content</div>

        {showOptionalContent && (    // only renders when showOptionalContent === true
            <div>Optionally rendered content</div>
        )}

        <span>Always rendered content</span>

        {showOptionalContent && (    // only renders when showOptionalContent === true
            <span>Optionally rendered span</span>
        )}
    </div>
)

Upvotes: 2

Related Questions