0

Edited to add solution at bottom

I have a project created with React and Typescript.

There is a parent component (Home) that displays a child component depending on the value of the state variable 'currentDemo'. The goal is to have a navigation component that will display whatever item was clicked. Each nav item has an id associated that relates to the component to be displayed. Ie, nav item 'a' should display component 'a', nav item 'b' should show component 'b', etc. Here is a snippet of the code.

Home.tsx (Parent):

import React, { useState } from 'react';
import { Intro } from 'app/components/intro/Intro';
import { SidebarNav } from 'app/components/sidebarNav/SidebarNav';
import { ComponentA } from 'app/components/ComponentA/ComponentA';
import { ComponentB } from 'app/components/ComponentB/ComponentB';

export function Home() {
  //use state to track which demo is currently displayed ('intro' is default)
  const [currentDemo, setCurrentDemo] = useState('intro');

  return (
    <>
      <Header />
      <div className="home">
        <SidebarNav setCurrentDemo={setCurrentDemo} />
        {currentDemo === 'intro' && <Intro />}
        {currentDemo === 'ComponentA' && <ComponentA/>}
        {currentDemo === 'ComponentB' && <ComponentB/>}
      </div>
    </>
  );
}


SidebarNav.tsx(child):

import React, { useState } from 'react';

const navData = [
  {
    title: 'Introduction',
    id: 'intro'
  },
  {
    title: 'Component A',
    id: 'ComponentA'
  },
  {
    title: 'Component B',
    id: 'ComponentB'
  }
];

export function SidebarNav(setCurrentDemo: any) {

  //GOAL: PASS ID OF SELECTED NAV ITEM TO PARENT COMPONENT AND SET VALUE OF 'CURRENTDEMO' TO THAT ID
  const handleCurrentClick = (id: any) => {
    if (id === 'intro') {
      setCurrentDemo('ComponentA');
    } else if (id === 'ComponentA') {
      setCurrentDemo('ComponentB');
    } else if (id === 'ComponentB') {
      setCurrentDemo('intro');
    }
  };

  return (
    <div className="sidebarNav">
      <div className="sidebarNav__container">
        {navData?.map((item, index) => (
          <div key={index}>
            <button
              onClick={() => {
                handleCurrentClick(item.id);
              }}
              id={item.id}
            >
              {item.title}
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

The specific implementation of Component A and B don't matter for this scenario. I've tested by manually setting the value of 'currentDemo' and the correct demo will display. I also confirmed that the id's for each nav item are correctly displaying via console.log(item.id).

How can I pass the pass the value of the id from SidebarNav to Home, setting the value of currentDemo to the ID of the nav item that was clicked? I feel like I'm close, but it's not quite right.

When clicking any of the nav elements there is a console error stating that setCurrentDemo is not a function. Which makes sense because it's the setter for the state, but how can I specify that we want to actually set currentDemo to the value of the item's ID?

Here is the solution that worked for this application. Changes made are in the navigation component. Added an interface in the nav and adjusted as such:

interface SidebarNavProps {
  setCurrentDemo: React.Dispatch<SetStateAction<string>>;
}

export function SidebarNav(props: SidebarNavProps) {
  const { setCurrentDemo } = props;

...rest of function remains the same 

};


2 Answers 2

1

Each component receives props as an object. In SidebarNav component, props will look like this { setCurrentDemo } :any not setCurrentDemo:any.

Here's the interface for SidebarNav Component

import { SetStateAction } from "react";

interface SidebarNavProps {
  setCurrentDemo: SetStateAction<string>
}

And your SidebarNav component will look like this:

export function SidebarNav(props: SidebarNavProps) {
  const { setCurrentDemo } = props;

  //GOAL: PASS ID OF SELECTED NAV ITEM TO PARENT COMPONENT AND SET VALUE OF 'CURRENTDEMO' TO THAT ID
  const handleCurrentClick = (id: any) => {
    if (id === 'intro') {
      setCurrentDemo('ComponentA');
    } else if (id === 'ComponentA') {
      setCurrentDemo('ComponentB');
    } else if (id === 'ComponentB') {
      setCurrentDemo('intro');
    }
  };

  return (
    <div className="sidebarNav">
      <div className="sidebarNav__container">
        {navData?.map((item, index) => (
          <div key={index}>
            <button
              onClick={() => {
                handleCurrentClick(item.id);
              }}
              id={item.id}
            >
              {item.title}
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

This will fix that error and you can store the id in state using setCurrentDemo.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I had to make a small change to the interface, basically setCurrentDemo: React.Dispatch<SetStateAction<string>>; It is working in my application now. I appreciate the feedback.
0

you can identify state in parent and set this state on child component to pass data from child to parent

1 Comment

I understand the words in your comment, but an example would go a long way to show exactly how this would work!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.