I’m trying to build an app with a chat block that does not refresh on page change. The child pages contain prompts to save the user from typing common responses. All my pages live within a /board directory that has a top level page called ‘BoardContainer,tsx’:
'use client'
import React, { ReactElement, ReactNode } from 'react';
import { useState } from 'react';
import { usePathname } from 'next/navigation';
import ChatBlock from '../components/ChatBlock/ChatBlock';
import AboutPage from '../dashboard/about/background/page';
interface BoardContainerProps {
children: ReactNode;
}
const BoardContainer: React.FC<BoardContainerProps> = ({ children }) => {
const [selectedPrompt, setSelectedPrompt] = useState('');
const pathname = usePathname();
const sendPrompt = (prompt: string) => {
setSelectedPrompt(prompt);
}
const childrenWithProps = React.Children.map(children, child => {
console.dir(child);
if (React.isValidElement(child)) {
return React.cloneElement(child as ReactElement<any>, { sendPrompt });
}
console.dir(child);
return child;
});
console.dir(pathname);
return (
<>
<>
{ pathname === '/board/about' ? <AboutPage sendPrompt={sendPrompt} /> : <PageContent sendPrompt={sendPrompt} /> }
{/* This works but not suitable for more than 2 child pages */}
{/* childrenWithProps */}
{/* this doesn't work either */}
{/* children */}
<>
<>
<ChatBlock
prompt={selectedPrompt}
/>
</>
</>
)
}
export default BoardContainer;
I figured a work-around using usePathname and essentially hard coding the child value and passing the sendPrompt function, but this is cumbersome.
I tried using React.cloneElement, but I’m either using this incorrectly or misunderstanding something. How can I pass the sendPrompt function via { children }?
2
Answers
You’ll use a callback function…
<ChatBlock prompt={selectedPrompt} setSelectedPrompt={setSelectedPrompt} />
Then for the prop in chat block component itself…
setSelectedPrompt: React.Dispatch<React.SetStateAction<string>>;
Then for the place you’re using it in your chat block code…
onClick={() => setSelectedPrompt('prompt1')}
One way to solve this is to use
useContext
linkCreate a
provider
inBoardContainer
Subscribe to the
context
and getsendPrompt
in yourclient side
components like this:Working sample: https://stackblitz.com/edit/stackblitz-starters-yqbyrm?file=app%2Flayout.tsx