Reputation: 446
Is there a way to preserve the state when calling a custom react hook from separate components? I made a simple example here but I was thinking of using the same logic in my app to store a fetch call to an api and use the data in different places in my app without calling the api more than once.
import React, { useState, useEffect } from 'react';
function useCounter(intialCount = 0){
const [count, setCount] = useState(0);
// Similar to componentDidMount and componentDidUpdate:
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
});
return [count, setCount];
}
const AnotherComponent = () => {
const [count] = useCounter();
return <div>{count}</div>
}
export default function App() {
// Call custom hook `useCounter` to reuse Counter logic
const [count, setCount] = useCounter(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<button onClick={() => setCount(count - 1)}>
Decrement
</button>
<AnotherComponent />
</div>
);
}
In this example, is it possible for AnotherComponent
to have the same count as App
. I dont want to use context either in my app component for performance reasons because the data I would get from an api is a large list.
Upvotes: 2
Views: 5289
Reputation: 467
Use SWR or React Query, they will automatically cache your data from the server and stop duplicate callings.
Upvotes: -1
Reputation: 12071
If you don't want to use context then it is possible to achieve what you want using some shared state outside of the hook:
let sharedCount = 0;
function useCounter(initialCount) {
const [count, _setCount] = useState(sharedCount);
// On first run, set initial count
useEffect(() => {
if (initialCount !== undefined) {
sharedCount = initialCount;
}
}, []);
// If shared count is changed by other hook instances, update internal count
useEffect(() => {
_setCount(sharedCount);
}, [sharedCount]);
const setCount = (value) => {
sharedCount = value; // Update shared count for use by other hook instances
_setCount(value); // Update internal count
};
return [count, setCount];
}
Upvotes: 4
Reputation: 21297
Yeap, you can easily achieve your goal by setting a Context
to provide a centralized state and a custom hook to access that state in a modular way.
Let's assume that a want to share foo
with my entire application.
FooContext.js
import { createContext, useState } from 'react'
export const FooContext = createContext()
const { Provider } = FooContext
export const FooProvider = ({ children }) =>{
const [foo, setFoo] = useState('bar')
return(
<Provider value={{foo, setFoo}}>
{ children }
</Provider>
)
}
foo
with FooProvider
<FooProvider>
<RestOfApp/>
</FooPrivider>
foo
easily accessibleuseFoo.js
import { useContext } from 'react'
import { FooContext } from './FooContext.js'
export const useFoo = () =>{
const { foo, setFoo } = useContext(FooContext)
return [foo, setFoo]
}
FooProvider
)import { useFoo } from './useFoo'
const ComponentWithFoo = () =>{
const [foo, setFoo] = useFoo()
const changeFoo = value => setFoo(value)
return <p> { foo } </p>
}
Notice that besides hooks you could also use HOCs or render props.
Upvotes: 0