Reputation: 11
My first component is a server-component holding a list of items which I load from a database. This list should be rendered server-side because of seo. My second component is a client-component holding an input field.
When the user types something in the input field, I want to filter the item list regarding to the input.
I can't find a way to share the input state between the two components so the component holding the item list can be a server-component. If that's not possible is there a way to make it a client component so it is still seo friendly?
Probably there will be a very general solution for this type of problem, but I am not that long in nextjs development and this is the first time I encountered it :/
I tried to break the problem down to the minimum.
So I have this component holding an inputField and outputField:
const SharedContextVariable = () => {
return (
<div className='w-full h-screen flex flex-col gap-5 justify-center items-center'>
<InputField />
<OutputField />
</div>
)
}
This is the inputField:
const InputField = () => {
const [input, setInput] = useState("");
return (
<input className='text-black p-2' placeholder='input' value={input} onChange={(e) => setInput(e.target.value)} />
)
}
And this is the outputField:
const OutputField = () => {
return (
<div className='w-1/2 h-64 border-[1px] border-white flex justify-center items-center'>
<p className='text-white '>
{/* input should be displayed here */}
</p>
</div>
)
}
How to display the input of the inputField in the outputField in realtime while remaining it as a server-component (if that is possible)?
Upvotes: 1
Views: 1903
Reputation: 11
After some research I found out by myself. The solution is to use url based props.
Here is the extended example code so it has the expected behaviour.
This is the parent component (page.tsx):
import React from 'react'
import InputField from './components/inputField'
import OutputField from './components/outputField'
type Props = {
searchParams: { [key: string]: string | string[] | undefined },
}
const SharedState = (props: Props) => {
const searchParams = props.searchParams;
return (
<div className='w-full h-screen flex flex-col gap-5 justify-center
items-center'>
<InputField />
<OutputField searchParams={searchParams} />
</div>
)
}
export default SharedState
The client-component (inputField.tsx):
'use client';
import React, { useState, useEffect } from 'react'
import { useDebounce } from 'use-debounce';
import { useRouter } from 'next/navigation';
const InputField = () => {
const [input, setInput] = useState("");
const [query] = useDebounce(input, 500);
const router = useRouter();
useEffect(() => {
if (!query) {
router.push('/sharedState');
}
else {
router.push(`/sharedState?query=${query}`)
}
}, [query]);
return (
<input
className='text-black p-2'
placeholder='...'
value={input}
onChange={(e) => setInput(e.target.value)}
/>
)
}
export default InputField
The server-component (outputField.tsx):
type Props = {
searchParams: { [key: string]: string | string[] | undefined };
};
const OutputField = (props: Props) => {
const searchParams = props.searchParams;
const query = searchParams.query;
return (
<div className='w-1/2 h-64 border-[1px] border-white flex justify-
center items-center'>
<p className='text-white '>
{query}
</p>
</div>
)
}
export default OutputField
Upvotes: 0