Home > Software engineering >  How can I render out a piece of content dynamically only once from mapped through data, despite pote
How can I render out a piece of content dynamically only once from mapped through data, despite pote

Time:11-11

I have an object of data I am pulling through from a CMS to create a blog and am mapping through the content object in order to render out the main body of the blog.

I have created a ternary operator to essentially say, that if the line of text has a type of 'strong', make the font bold, otherwise if it has a type of 'hyperlink', make the piece of text a link within an tag.

The issue I'm having is that some pieces of text are both 'bold' and 'hyperlinks', and so it is rendering out the sentence twice, how can I ensure that when the type is both 'bold' & 'hyperlink', it only renders once?

This is what my data looks like:

enter image description here

and here is my file where I return this data on the frontend:

 <div className='text-left mt-12 text-white'>
          <h1 className='text-5xl mb-4 font-header text-blue-500'>
            {RichText.asText(data.title)}
          </h1>
          {data.content.map((t, i) => {
            return (
              <>
                {!t.spans[0] && (
                  <p className={`text-lg mt-6 opacity-80 ${t.type}`}>
                    {t.text}
                  </p>
                )}
                {t.spans.map((item) =>
                  item.type === 'strong' ? (
                    <p className={`text-xl mt-6 font-bold ${t.type}`}>
                      {t.text}
                    </p>
                  ) : item.type === 'hyperlink' ? (
                    <a
                      href={item.data.url}
                      target='_blank'
                      className={`text-lg opacity-80 mt-6 text-blue-500 ${t.type}`}>
                      {t.text}
                    </a>
                  ) : item.type === 'list-item' ? (
                    <ul className='list-disc'>
                      <li className='text-lg mt-4 text-white'>{t.text}</li>
                    </ul>
                  ) : (
                    <p
                      className={`text-lg opacity-80 mt-6 font-bold ${t.type}`}>
                      {t.text}
                    </p>
                  )
                )}
              </>
            );
          })}
        </div>

I'm sure this is simple but I wondered the best way to handle something like this?

Thanks in advance!

CodePudding user response:

Don't make your logic switching cases on type.

Try something like this:

const styleProps = spans.reduce((acc, span) => {
   if (span === 'strong'){
      acc['font-weight'] = 'bold';
   }
   if (span === 'something-else'){
      acc['some-css-prop'] = 'some-value';
   }
   ...
   return acc;
}, {})

and then you will have an accumulator (styleProps) with all the necessary props needed to style your component.

<YourComponent className="my-constant-class-name" style={{...styleProps}} />

You can generalize this idea:

ex.

const MyComponentProps = spans.reduce((acc, span) => {
   if (span === 'strong'){
      acc.style['font-weight'] = 'bold';
   }
   if (span === 'hyperlink'){
      acc['href'] = 'www.example.com';
   }
   ...
   return acc;
}, {});

and also

let MyComponent = null;
switch(type){
  case 'hyperlink':
     MyComponent = (props) => <a {...props} />;
     break;
  case 'text':
     MyComponent = (props) => <p {...props} />;
     break;
  case 'bullet':
     MyComponent = (props) => <li {...props} />;
     break;

and then

<MyComponent {...MyComponentProps} />
  • Related