Looking for some guidance on how to structure the below components to trigger an (export) method in one component from another 'sibling' component.
Using a download button contained in <DownloadChartButton> in the Card Header, I want to download a chart contained in my PaginatedRechartsChart component as a PNG. I currently have the components structured like below. DownloadChartButton needs to access the recharts chart contained in my <PaginatedRechartsChart> component. Hoping to keep DashboardCard, DownloadChartButton, and PaginatedRechartsChart generic so they can be applied in many places, hence the current structure.
Question: Is there a better way to structure my components to avoid the React anti-pattern of triggering child methods from parent components?
Thank you for your help!
Pseudo-code:
export const LineChartByDay = () => {
const [data, setData] = React.useState([{'date':'2021-01-01': 'count':34})
return (
<DashboardCard
headerItems={<DownloadChartButton data={data}/>}
>
<PaginatedRechartsChart data={data}/>
</DashboardCard>
)
}
import {LineChart} from 'recharts'
export const PaginatedRechartsChart = (data) => {
// ... extra code for client-side pagination, etc.
return (
<ResponsiveContainer>
<LineChart data={data}/>
</ResponsiveContainer>
)
}
export const DashboardCard = ({ title, actions, children, error, loading }: { title: string, actions?: React.ReactNode, children?: React.ReactNode, error?: any, loading?: boolean }) =\> {
return (
<Card>
<CardHeader
title={title}
action={actions}
></CardHeader>
<CardContent>
{error && <ErrorAlertBar title={error}/>}
{loading && <CircularProgress/>}
{children}
</CardContent>
</Card>
)
}
export const DownloadChartButton = (data) => {
// ... CSV download logic (takes a list of objects in data, exports to CSV)
// ... PNG download logic
const [getPng, { ref }] = useCurrentPng();
//Ideally we'd have chart download logic in this component so we don't have to copy it into every chart component
const handleDownload = React.useCallback(async () => {
const png = await getPng();
// Verify that png is not undefined
if (png) {
// Download with FileSaver
FileSaver.saveAs(png, 'myChart.png');
}
}, [getPng]);
return (
<MenuButton>
<MenuItem>CSV</MenuItem>
<MenuItem>PNG</MenuItem>
</MenuButton>
)
}
From what I see online, my current thought is using a ref in the parent component and passing that to PaginatedRechartsChart and DownloadChartButton... but I'm seeing online that this is an anti-pattern for React (i.e. https://stackoverflow.com/a/37950970/20391795)
Aucun commentaire:
Enregistrer un commentaire