2

I want to add several infos sections in my front page, each having a button linking to an associated page on my website. Instead of writing a very large InfoSection component comprising all the sections (there will be 4 or 5), I tried to write only one section 'template' in the InfoSection component, and use a Data.js file where each object containing the information about each section, then displaying them on the main page like this:

<InfoSection {...homeObjOne}/>
<InfoSection {...homeObjTwo}/>
<InfoSection {...homeObjThree}/>

I then try to pass each page link in each object of Data.js, but then whenever I click on it, I receive the TypeError: Cannot read properties of undefined (reading 'pathname') I assume I'm doing something wrong with the component of 'buttonLabel' in the object from Data.js. What could I do to make it work?

The button works if I get rid of that 'buttonLabel' and just put a to='page1' in the <Button> component of index.js (<Button to='page1'>), but that would mean each section links to the same page and I need each button to link to a different page...

The code is below (using only 2 sections at the moment, linking to page1 and page2)

Data.js from the InfoSection component

import React from 'react';
import { Link } from 'react-router-dom';
export const homeObjOne = {
    description: <p>page 1</p>,
    buttonLabel: <Link to="page1" target='_blank' style={{ textDecoration: 'none' }}>Go to page 1</Link>
};
export const homeObjTwo = {
    description: <p>page 2</p>,
    buttonLabel: <Link to="page2" target='_blank' style={{ textDecoration: 'none' }}>Go to page 2</Link>
};

index.js of the InfoSection component

import React, { useState, useEffect} from 'react';
import { Button } from '../ButtonElements';
import { InfoContainer, InfoWrapper, InfoRow, Column1, Column2, TextWrapper, TopLine, Heading, Subtitle, BtnWrap, ImgWrap, Img  } from './InfoElements';
import VizSensor from 'react-visibility-sensor';
import { Fade } from '@mui/material';

const InfoSection = ({lightBg, id, imgStart, topLine, lightText, headline,darkText, description, buttonLabel, img, alt, primary, dark, dark2}) => {

    let [active, setActive] = useState(false);

    return (
        <>
            <InfoContainer lightBg={lightBg} id={id}>
                <InfoWrapper>
                    <InfoRow imgStart={imgStart}>
                        <Column1>
                            <VizSensor onChange={(isVisible) => {
                                        if(isVisible){
                                            setActive(isVisible);
                                        }
                                        }}
                            >
                                <Fade in={active} timeout={1000} >
                                    <TextWrapper>
                                        <TopLine>{topLine}</TopLine>
                                        <Fade in={active} timeout={1000} style={{ transitionDelay: `400ms` }}>
                                            <Heading lightText={lightText}>{headline}</Heading>
                                        </Fade>
                                        <Fade in={active} timeout={1000} style={{ transitionDelay: `800ms` }}>
                                            <Subtitle darkText={darkText}>{description}</Subtitle>
                                        </Fade>
                                        <BtnWrap>
                                            <Button
                                            smooth={true}
                                            duration={500}
                                            spy={true}
                                            exact="true"
                                            offset={-80}
                                            primary={primary ? 1 : 0}
                                            dark={dark ? 1: 0}
                                            dark2={dark2 ? 1 : 0}
                                            >{buttonLabel}</Button>
                                        </BtnWrap>
                                    </TextWrapper>
                                </Fade>
                            </VizSensor>
                        </Column1>
                        <Column2>
                            <ImgWrap>
                                <Img src={img} alt={alt}/>
                            </ImgWrap>
                        </Column2>
                    </InfoRow>
                </InfoWrapper>
            </InfoContainer> 
        </>
    )
}

export default InfoSection

The ButtonElements.js file:

import styled from "styled-components";
import { Link } from "react-router-dom";


export const Button = styled(Link)`
    border-radius: 50px;
    background: ${({primary}) => (primary ? '#F59AA6' : '#010606')};
    white-space: nowrap;
    padding: ${({fontBig}) => (fontBig ? '20px' : '16px')};
    outline: none;
    border: none;
    cursor: pointer;
    display: flex;
    justify-content: center;
    text-decoration: none;
    align-items: center;
    transition: all 0.2s ease-in-out;

    &:hover {
        transition: all 0.2s ease-in-out;
        background: ${({primary}) => (primary ? '#fff' : '#F59AA6')};
    }
`
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Alex Nedop
  • 29
  • 3

1 Answers1

0

Each Button component is already a link, so you are effectively placing a link within a link, or more accurately, an anchor <a> tag within an anchor tag, which isn't valid HTML. The buttonLabel can be just about anything renderable, except another link.

I suggest placing the link props on the Button and have buttonLabel return the button/link text.

export const homeObjOne = {
  description: <p>page 1</p>,
  buttonLabel: "Go to page 1"
};

export const homeObjTwo = {
  description: <p>page 2</p>,
  buttonLabel: "Go to page 2"
};

...

<BtnWrap>
  <Button
    smooth
    duration={500}
    spy
    exact
    offset={-80}
    primary={primary ? 1 : 0}
    dark={dark ? 1: 0}
    dark2={dark2 ? 1 : 0}
    to="page2"      // <-- link props here
    target='_blank' // <-- link props here
  >
    {buttonLabel}
  </Button>
</BtnWrap>

Move the button/link text decoration CSS to the Button component.

export const Button = styled(Link)`
  border-radius: 50px;
  background: ${({ primary }) => (primary ? '#F59AA6' : '#010606')};
  white-space: nowrap;
  padding: ${({ fontBig }) => (fontBig ? '20px' : '16px')};
  outline: none;
  border: none;
  cursor: pointer;
  display: flex;
  justify-content: center;
  text-decoration: none;
  align-items: center;
  transition: all 0.2s ease-in-out;
  textDecoration: none; // <-- text decoration here

  &:hover {
    transition: all 0.2s ease-in-out;
    background: ${({ primary }) => (primary ? '#fff' : '#F59AA6')};
  }
`;
Drew Reese
  • 165,259
  • 14
  • 153
  • 181