I'm having trouble getting datas from redux when I refresh my page
const [filters, setFilters] = useState<string[]>(props.filters);
useEffect(() => {
(() => {
if (!_.isEqual(filters, props.filters)) {
setFilters(props.filters);
}
})();
});
My filters are undefined even though when I check redux devtools, there is datas in filters.
I need to trigger an event in my front to display my filters.
Anyone have an idea please ?
Edit:
(if I click any element in my page it load my filters)
If I add a setTimeout on refresh it works but I'm not sure using setTimeout is a solution
useEffect(() => {
setTimeout(() => {
setFilters(props.filters);
}, 1500);
}, []);
May be you just missed returning the inner functions:
Or just call the setFilters like:
useEffect(() => {
if (!_.isEqual(filters, props.filters)) {
setFilters(props.filters);
}
});
Related
I am having problem rendering ui before redirect in react. I has a variable is called from api, i want to check if it is 'x' then will redirect. But ui will render before redirect.
Bellow is my code:
useLayoutEffect(() => {
getProfile().then((res) => {
setIsLoading(true);
if (res) {
redirectByUserType(res.data.type); // redirect to /home
}
});
}, []);
I tried using useLayoutEffect but not working.
Please help me, thank you so much.
If you don't want to render until getProfile() has finished, then have a state variable which tracks whether it is finished. If it hasn't finished, return null to render nothing. If it has, return whatever you want to render. I would normally call this state variable loading, but you seem to already have one with that name, who's purpose i don't know. Maybe you can piggy back on that, maybe you need a separate one:
const [ready, setReady] = useState(false);
useEffect(() => {
getProfile().then(res => {
setIsLoading(true);
if(res) {
redirectByUserType(res.data.type);
} else {
setReady(true)
}
});
}, []);
if (!ready) {
return null;
}
return (
<div>Something</div>
);
I am new to react and am having trouble figuring out why the data inside my Content component does not re-render on refresh.
When I visit one of the routes, say /sentences-of-the-day, and then I refresh the page, it seems all the stuff inside content is gone.
Can someone please help me out?
Here is the code sandbox:
https://codesandbox.io/s/mainichome-v7hrq
You need to load the data once the component is mounted (using useEffect) set to local state to trigger the render. In each refresh, mounting happens again and you have the data after each refresh.
Define another function in content.data.js
export const getContentData = () => {
return Promise.all(contentDataStories.map((func) => func()));
};
In your content.component.jsx
import { getContentData } from "./content.data.js";
const [content, setContent] = useState([]);
useEffect(() => {
(async () => {
setContent(await getContentData());
})();
}, []);
Code sandbox => https://codesandbox.io/s/mainichome-forked-4sx5n?file=/src/components/content/content.component.jsx:302-449
The problem is here:
import contentData from "./content.data.js";
//...
const [content] = useState(contentData);
That imports contentData and then sets it as state.
However, that value is asynchronous.
const contentData = [];
contentDataStories.forEach(function (func) {
func().then((json) => {
contentData.push(json);
});
});
export default contentData;
It's just [] until those promises reoslve.
So what's happening is that the page is loading fine, but the content from that file hasn't loaded before the first render.
This is a race condition. Which will happen first, the data loading or the render? Sometimes the render wins and everything is fine, but sometimes it doesn't and you get a blank page.
To fix it, you need to make React aware of your data loading, so that it can re-render when the data finishes loading.
First make a function that does your async loading:
export function getContentData() {
return new Promise((resolve) => {
// fetch async stuff here
resolve(myDataHere)
})
}
And then call that from a useEffect, which sets the state.
function Content() {
const { titleParam } = useParams();
const [content, setContent] = useState(contentData);
useEffect(() => {
getContentData().then(setContent);
}, [getContentData]);
//...
}
Now when you component mounts, it calls getContentData. And then that promise resolves, it sets the state, triggering a a new render.
I have a working useEffect to call my google analytics when changing page.
This works fine when changing pages but when you initially load for the first time or refresh it does not call the router.events.on
this is my code
useEffect(() => {
if (cookies === true) {
router.events.on("routeChangeComplete", () => {
ReactGA.pageview(window.location.pathname);
});
return () => {
router.events.off("routeChangeComplete", () => {
ReactGA.pageview(window.location.pathname);
});
};
}
}, [router.events]);
I thought of using an other useEffect to initially call the reactGA but then when changing page it would be called twice, which is not good.
any idea on how to make this work on the initial page load?
That's expected behaviour - router.events is only triggered on client-side page navigations initiated by the Next.js router.
You can call ReactGA.pageview on a separate useEffect to handle initial page loads.
useEffect(() => {
if (cookies === true) {
ReactGA.pageview(window.location.pathname);
}
}, []);
I quite new to GraphQL. I'm trying to use useLazyQuery hook for my onBtnClick function. The button supposed to query and do something everytime on click.
The first time i click on the button the data return is undefined, only second try onwards then it works. This is some sample code below:
const [getItemList, { loading, data}] = useLazyQuery(ItemList, { fetchPolicy: 'network-only' });
const onBtnClick = () => {
getItemList();
if (loading) {
//do something
});
if (data) {
//do another thing
}
}
return (
<div>
<button onClick={onBtnClick}>Something</button>
</div>
)
Could anyone guide me or explain on this?
Cause data in onBtnClick function is not newest data. You need a useEffect to listen data and loading change.
useEffect(() => {
console.log(data, loading)
}, [data, loading])
A react app using hooks. In useEffect there is an api-call to populate content on page.
Each element fetched is clickable. And a click will open details for the clicked element in a new browser window/tab.
When working in the new window, the user can make changes on that object. The user will then close that tab or at least just go back to the main window/tab.
Question is how I can detect that the user is coming back to the main window. This is because I want to re-fetch data from API. Thus, I want to rerun useEffect.
While googling I found this:
https://www.npmjs.com/package/react-page-visibility
Is that really what I'm looking for? Reading the docs I'm not really sure if that can be the solution to my issue. Is there another way to solve this?
You can use the visibilitychange event to achieve that:
const onVisibilityChange = () => {
if (document.visibilityState === 'visible') {
console.log("Tab reopened, refetch the data!");
}
};
useLayoutEffect(() => {
document.addEventListener("visibilitychange", onVisibilityChange);
return () => document.removeEventListener("visibilitychange", onVisibilityChange);
}, []);
Codesandbox
With React 18 you can use 'visibilitychange' with react brand new hook useSyncExternalStore
export function useVisibilityChange(serverFallback: boolean) {
const getServerSnapshot = () => serverFallback;
const [getSnapshot, subscribe] = useMemo(() => {
return [
() => document.visibilityState === 'visible',
(notify: () => void) => {
window.addEventListener('visibilitychange', notify);
return () => {
window.removeEventListener('visibilitychange', notify);
};
},
];
}, []);
Gist with hook
P.S:Don't forget cross-browser usage