How to use await call inside client component
Answered
Horse guard wasp posted this in #help-forum
Horse guard waspOP
I have been facing a challenge with client components, await, async function and useEffect collectively together for the past few days, whilst using Next.JS 13 app folder structure.
I have a standard page which imports a client search component, which has useStates and useEffect.
I also am using the i18n and by calling "await useTranslation( 'name')", which in turn would require me to change the client component to async for it to work. By doing so, then everytime I search and fire the useEffect, the whole page goes into multiple re-render.
Clearly I can see you cant have async and useEffect working together and I was wondering if anyone has a solution for this. I have already tried decoupling as much as possible, but once the await call and asyn component come into play, the whole thing goes into re-render.
Thanks
I have a standard page which imports a client search component, which has useStates and useEffect.
I also am using the i18n and by calling "await useTranslation( 'name')", which in turn would require me to change the client component to async for it to work. By doing so, then everytime I search and fire the useEffect, the whole page goes into multiple re-render.
Clearly I can see you cant have async and useEffect working together and I was wondering if anyone has a solution for this. I have already tried decoupling as much as possible, but once the await call and asyn component come into play, the whole thing goes into re-render.
Thanks
Answered by Horse guard wasp
SearchComponent is the issue, the await call to the useTranslation and the async nature of the component, conflicts with useEffect and everytime I enter a value in the input, which triggers the useEffect, the whole page re-renders and that includes everything on the page, and not just the component. The moment I take that out and remove async, functions normally.
13 Replies
Atlantic salmon
can you send some code? 🙂
Horse guard waspOP
export default function Page({
params: { lng }
}: {
params: { lng: string }
}) {
return (
<>
<SearchComponent lng={lng} />
</>
)
} export default function SearchComponent (props: any) {
const { t } = await useTranslation(props.lng, 'faq')
const [searchQuery, updateSearchQuery] = useState<string>('')
const [searchResults, setSearchResults] = useState<any[]>([])
...
useEffect(() => {
if (searchQuery.length >= 3) {
getSearchResults(searchQuery)
return
} else {
setSearchResults([])
return
}
}, [searchQuery])
return (
<>
<input
name='search'
type='search'
onKeyUp={onSearch}
onChange={(e: any) => handleChange(e)}
/>
{hits.length > 0 ? (
<>
<ul >
{result.map((data: any, i: number) =>
i < 5 ? (
<li key={data.refIndex} className='py-2 px-3'>
<Link href={`/${props.lng}/path/${data.item.slug}`}>
Title
</Link>
</li>
) : (
''
)
)}
</ul>
</>
) : (
''
)}
</>
)
}import { createInstance } from 'i18next'
import resourcesToBackend from 'i18next-resources-to-backend'
import { initReactI18next } from 'react-i18next/initReactI18next'
import { getOptions } from './settings'
const initI18next = async (lng: any, ns: any) => {
// on server side we create a new instance for each render, because during compilation everything seems to be executed in parallel
const i18nInstance = createInstance()
await i18nInstance
.use(initReactI18next)
.use(resourcesToBackend((language: any, namespace: any) => import(`./locales/${language}/${namespace}.json`)))
.init(getOptions(lng, ns))
return i18nInstance
}
export async function useTranslation(lng: any, ns: any, options = {}) {
const i18nextInstance = await initI18next(lng, ns)
return {
// @ts-ignore
t: i18nextInstance.getFixedT(lng, Array.isArray(ns) ? ns[0] : ns, options.keyPrefix),
i18n: i18nextInstance
}
}Sorry it came out abit messy, the issue is in the FaqSearch and the i18n. I have taken out the useTransalation and it works perfectly fine. Whenever I introduce that and change the function to async, starts with the re-rendering saga.
not sure about i18n but you definetly can use promises inside use Effect
why not use
.then() callbacks?Horse guard waspOP
I just did a workaround, by initiating the useTranslation at Page level and passing the value through props. It works and doesnt refresh, but surely there should be a cleaner solution to have that inside of the component I would assume.
I did try that as well, but sadly was delivering the same results.
I did try that as well, but sadly was delivering the same results.
@Horse guard wasp typescript
export default function SearchComponent (props: any) {
const { t } = await useTranslation(props.lng, 'faq')
const [searchQuery, updateSearchQuery] = useState<string>('')
const [searchResults, setSearchResults] = useState<any[]>([])
...
useEffect(() => {
if (searchQuery.length >= 3) {
getSearchResults(searchQuery)
return
} else {
setSearchResults([])
return
}
}, [searchQuery])
return (
<>
<input
name='search'
type='search'
onKeyUp={onSearch}
onChange={(e: any) => handleChange(e)}
/>
{hits.length > 0 ? (
<>
<ul >
{result.map((data: any, i: number) =>
i < 5 ? (
<li key={data.refIndex} className='py-2 px-3'>
<Link href={`/${props.lng}/path/${data.item.slug}`}>
Title
</Link>
</li>
) : (
''
)
)}
</ul>
</>
) : (
''
)}
</>
)
}
Tan
u can do
```typescript
// Your Code Here
```
and that will look like:
```typescript
// Your Code Here
```
and that will look like:
// Your code hereit will be easier to read
@Tan u can do
\`\`\`typescript
// Your Code Here
\`\`\`
and that will look like:
typescript
// Your code here
Horse guard waspOP
Just updated it. Thanks
Can you simplify the code to only where it matters? Like where are you trying to use await in client xomponents?
Horse guard waspOP
SearchComponent is the issue, the await call to the useTranslation and the async nature of the component, conflicts with useEffect and everytime I enter a value in the input, which triggers the useEffect, the whole page re-renders and that includes everything on the page, and not just the component. The moment I take that out and remove async, functions normally.
Answer