I'm trying to update a state as soon as the page comes to focus in react native with react native navigation, but if I log the value it still results in the old one.
useFocusEffect(
React.useCallback(() => {
if (route.params?.key !== null) {
setKey(route.params?.key);
console.log(route.params?.key) //These two console log give different values
console.log(key);
setLastTokenDate(route.params?.date);
}
}, [route.params?.chiave, route.params?.data]),
);
Try this:
useFocusEffect(
React.useCallback(() => {
if (route.params?.key !== null) {
setKey(route.params?.key);
setLastTokenDate(route.params?.date);
}
}, [route.params?.key, route.params?.date]),
);
useEffect(() => {
console.log(key);
}, [key]);
I think you will find where is your mistake
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>
);
Is there a way to check the next location via React Router? I am not interested in using Prompt solution. My goal is to set some condition on component unmount like:
useEffect(() => {
return () => {
if(nextRoute !== '/something') {
resetData();
}
};
}, []);
Is there a way to have a knowledge what is the nextRoute?
I have an object that is a copy for a property props.Job and I change it with:
const [jobData, setJobData] = React.useState<IjobData>();
const handleJobChange = (name, value) => {
setJobData({
...jobData, [name]: value
});
};
Now I wanted to save the value of jobData before the component unmounts
So:
React.useEffect(() => () => {
if (jobData !== props.Job) {
Save(jobData) // jobData is undefined
}
}, []);
No Good can't get the current state of jobData
So trying:
React.useEffect(() => () => {
if (jobData !== props.Job) {
Save(jobData) // jobData value is missing the last run of handleJobChange
}
}, [jobData]);
Also no good: jobData value is missing the last run of handleJobChange and also it is running before every run of handleJobChange and not only the "componentWillUnmount" event
Anyone can recommend a better way to figure the right event the will have the state so I can save it?
React.useEffect returns a function that can be used for clean up. i.e execute some code before unmounting/updating the component.
So for your use case, you can modify your useEffect like the following:
React.useEffect(() => () => {
return(()=>{
if (jobData !== props.Job) {
Save(jobData) // jobData is undefined
}
})
}, []);
The return statement will be executed before the unmounting of your component. For more details, you can check react's documentation
I'm using AWS Amplify and Formik in my React Native app. There's a screen in which a list of members will be displayed, and when the screen is loaded, the current user will be added by default to the list. Here's what I had before and works perfectly (I can see the current user in the list on the screen).
useEffect(() => {
if (values.members.length === 0) {
Auth.currentAuthenticatedUser().then(user => {
const owner: Member = {
id: user.attributes.sub,
name: user.attributes.name,
};
setFieldValue('members', [owner]);
});
}
}, []);
But, then, I created a UserContext and decided to replace the call to the amplify function Auth.currentAuthenticatedUser() with the user coming from the UserContext. Here's the new code:
const { user } = useContext(UserContext);
useEffect(() => {
if (values.members.length === 0) {
const owner: Member = {
id: user.attributes.sub,
name: user.attributes.name,
};
console.log("Owner", owner); // This displays the current user in the console
setFieldValue('members', [owner]);
}
}, []);
As I've commented in the code, the console.log() displays the current user, so the UserContext is working correctly, but for some reason setFieldValue doesn't work. Does anyone have any idea why this might be happening?
UPDATE:
I figured if I put setFieldValue() in the second code inside a setTimeout it works. But, in that case, shouldn't it also work if I changed useEffect(() => {}, []) to useEffect(() => {}, [user])?
You issue is because of an existing formik issue. So till it is fixed, just live with setTimeout or the solution you have mentioned.
Also see some of the other alternatives mentioned in the same link if it is useful.
Here's what I ended up doing. I'm posting this as an answer, but I'm still looking for an answer as to why this even happens.
const { user } = useContext(UserContext);
const [owner, setOwner] = useState(null as Member | null);
useEffect(() => {
if (values.members.length === 0) {
setOwner({
id: user.attributes.sub,
name: user.attributes.name,
});
}
}, []);
useEffect(() => {
setFieldValue('members', [owner]);
}, [owner]);
I'm using a componentDidUpdate function
componentDidUpdate(prevProps){
if(prevProps.value !== this.props.users){
ipcRenderer.send('userList:store',this.props.users);
}
to this
const users = useSelector(state => state.reddit.users)
useEffect(() => {
console.log('users changed')
console.log({users})
}, [users]);
but it I get the message 'users changed' when I start the app. But the user state HAS NOT changed at all
Yep, that's how useEffect works. It runs after every render by default. If you supply an array as a second parameter, it will run on the first render, but then skip subsequent renders if the specified values have not changed. There is no built in way to skip the first render, since that's a pretty rare case.
If you need the code to have no effect on the very first render, you're going to need to do some extra work. You can use useRef to create a mutable variable, and change it to indicate once the first render is complete. For example:
const isFirstRender = useRef(true);
const users = useSelector(state => state.reddit.users);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
} else {
console.log('users changed')
console.log({users})
}
}, [users]);
If you find yourself doing this a lot, you could create a custom hook so you can reuse it easier. Something like this:
const useUpdateEffect = (callback, dependencies) => {
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
} else {
return callback();
}
}, dependencies);
}
// to be used like:
const users = useSelector(state => state.reddit.users);
useUpdateEffect(() => {
console.log('users changed')
console.log({users})
}, [users]);
If you’re familiar with React class lifecycle methods, you can think
of useEffect Hook as componentDidMount, componentDidUpdate, and
componentWillUnmount combined.
As from: Using the Effect Hook
This, it will be invoked as the component is painted in your DOM, which is likely to be closer to componentDidMount.