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?
CodePudding user response:
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
.
CodePudding user response:
you can identify state in parent and set this state on child component to pass data from child to parent