skip to Main Content

I am running a function when the user clicks a button, this function updates my useState and adds an array into it as data. This data later on is passed into another webpage where the array objects are displayed in a different way. I’m running into an issue where, my useState is not updating and instead returns an empty array. I suspect it has something to do with the new page refreshing and not updating the useState. I am just not sure where to go from here.

I am using React-Router V6 for this

Here is my Parent webpage along with the button.

<div className="toggleButtons" key={id}>
  <Link
    to={"/DetailsPage"}
    onClick={toggledItem}
    state={{ data: data }}
    className="primary-ff boxyButton"
  >
    {buttonText}
  </Link>

  <a href={link} className="icon-link" target="_blank">
    <i className="fa-solid fa-arrow-up-right-from-square"></i>
  </a>
</div>

Here is where I am trying to pass an array list into my useState

const softiesInfo = pageContentList.find(({id}) => id == 1);
const palcoInfo = pageContentList.find(({id}) => id == 2);
const tlaxInfo = pageContentList.find(({id}) => id == 3);

const [data, setData] = useState({})

const toggledItem = () => {
  if (id === 1) {
    setData(softiesInfo);
  } else if (id === 2) {
    setData(palcoInfo)
  } else {
    setData(tlaxInfo)
  }
};

Here is where my data should be rendered on my second page.

export default function DetailsPage() {
  const location = useLocation();
  const data = location.state;
  return (
    <div className="header-wrap">
      <h1 className="primary-ff">{data.title}</h1>
      <img src={data.logoImg} alt={data.altLogo} />
    </div>
  )
});

I tried force feeding the data into my useState like this and this resulted successful, but I don’t see it being very efficient and would count as writing clean code.

const [data, setData] = useState({
  sectionName: "softies-section",
  title: "Softies Ice Cream-Under The Scoop",
  logoImg: softieslogo,
  altLogo: "softies-logo",
  img: softiesPlanner,
  altImg: "Career Day At Pinnacle",
  img2: softiesAccordion,
  constrainContent:
    "lorem a;sdkfj;alskdjfa lksdfjlaksjdl;fkjasldk;fjaslkdfjal;sdkjfalksdjf;laks;dj asflsngealj    sflsdajflkads",
  id: 1,
});

2

Answers


  1. Issue

    The issue here is that the Link component effects a navigation action immediately when it is clicked, and the passed state prop will include whatever the data value is at the time the link is clicked.

    Solution

    You can prevent the default link action from happening and effect the navigation action manually later. Unfortunately because enqueued React state updates are processed asynchronously you also can’t use the data state in the route state. What you can do however is to enqueue the state update alongside the imperative navigation action with the same value.

    Example:

    import { Link, useNavigate } from 'react-router-dom';
    
    ...
    
    const navigate = useNavigate();
    
    ...
    
    const toggledItem = (e) => {
      e.preventDefault(); // <-- prevent link navigation
    
      let data = {};
    
      switch(id) {
        case 1:
          data = softiesInfo;
          break;
    
        case 2:
          data = palcoInfo;
          break;
    
        case 3:
        default:
          data = tlaxInfo;
          break;
      }
    
      setData(data);
      navigate( // <-- imperative navigation
        "/DetailsPage",
        { state: { data } }
      );
    };
    

    <Link
      to="/DetailsPage"
      onClick={toggledItem}
      className="primary-ff boxyButton"
    >
      {buttonText}
    </Link>
    
    Login or Signup to reply.
  2. It seems like the issue you’re encountering might be related to passing state via React Router’s Link component. In React Router v6, the way to pass state via a link has changed compared to previous versions. Instead of using state directly on the Link component, you need to use the state prop of the navigate function from the useNavigate hook.

    Here’s how you can update your code to pass state properly:

    import { Link, useNavigate } from 'react-router-dom';
    
    // Parent component
    const ParentComponent = () => {
      const navigate = useNavigate();
    
      const toggledItem = () => {
        if (id === 1) {
          navigate('/DetailsPage', { state: { data: softiesInfo } });
        } else if (id === 2) {
          navigate('/DetailsPage', { state: { data: palcoInfo } });
        } else {
          navigate('/DetailsPage', { state: { data: tlaxInfo } });
        }
      };
    
      return (
        <div className="toggleButtons" key={id}>
          <button onClick={toggledItem} className="primary-ff boxyButton">
            {buttonText}
          </button>
          <a href={link} className="icon-link" target="_blank">
            <i className="fa-solid fa-arrow-up-right-from-square"></i>
          </a>
        </div>
      );
    };
    
    // DetailsPage component
    const DetailsPage = () => {
      const location = useLocation();
      const { data } = location.state || {}; // Ensure data is properly destructured with a default value
    
      return (
        <div className="header-wrap">
          <h1 className="primary-ff">{data?.title}</h1>
          <img src={data?.logoImg} alt={data?.altLogo} />
        </div>
      );
    };
    

    Make sure you have imported useNavigate from ‘react-router-dom’. With this approach, state will be properly passed to the destination page via the React Router navigation mechanism.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search