how to get state right after state change in react hooks - reactjs

Hi Everyone I am unable to get current state after setting up the state. I am calling a function Where I am passing that state but I am always getting default state in that function.
this is my State-
const [currentValue , setCurrentValue] = useState(one[0]); // where one[0] is string "Test"
this is my onchange function -
const getTest = useCallback((newValue:string) => {
setCurrentValue({
label:newValue,
value:newValue
});
getCurrentValue(currentValue.value);
getSortOrder()
}, [])
this is my getSortOrder function -
const getSortOrder =() => {
console.log(currentValue);
}
I am not getting updated state in getSortOrder function & getCurrentValue function. But yes If I am trying to console the state in render then it is showing me updated state but in function it is not updating. How can I achieve the updated state in both functions ?

If I get your question correctly then this might help:
const getTest = useCallback((newValue:string) => {
setCurrentValue({
label:newValue,
value:newValue
});
//try this code doing in useEffect
}, [])
useEffect(() => {
getCurrentValue(currentValue.value);
getSortOrder()
},[currentValue]); //Everytime currentValue changes it will give new state

This is happening because the 'setCurrentValue' function is an asynchronous function and the state is updated after both the functions 'getCurrentValue' and 'getSortOrder' have finished their execution.
One easy solution will be to pass the parameter 'newValue' to both the functions like this :
const getTest = useCallback((newValue:string) => {
setCurrentValue({
label:newValue,
value:newValue
});
getCurrentValue(newValue);
getSortOrder(newValue)
}, [])
const getSortOrder =(newValue) => {
console.log(newValue);
}
Or you can use the 'useEffect' functionality to trigger the functions after the value of the state has been updated like this :
const getTest = useCallback((newValue:string) => {
setCurrentValue({
label:newValue,
value:newValue
});
}, [])
useEffect(() => {
getCurrentValue();
getSortOrder()
},[currentValue]);

Related

React - set state doesn't change in callback function

I'm not able to read current state inside refreshWarehouseCallback function. Why?
My component:
export function Schedules({ tsmService, push, pubsub }: Props) {
const [myState, setMyState] = useState<any>(initialState);
useEffect(() => {
service
.getWarehouses()
.then((warehouses) =>
getCurrentWarehouseData(warehouses) // inside of this function I can without problems set myState
)
.catch(() => catchError());
const pushToken = push.subscribe('public/ttt/#');
const pubSubToken = pubsub.subscribe(
'push:ttt.*',
refreshWarehouseCallback // HERE IS PROBLEM, when I try to read current state from this function I get old data, state changed in other functions cannot be read in thi function
);
return () => {
pubsub.unsubscribe(pubSubToken);
push.unsubscribe(pushToken);
};
}, []);
...
function refreshWarehouseCallback(eventName: string, content: any) {
const {warehouseId} = myState; // undefined!!!
case pushEvents.ramp.updated: {
}
}
return (
<Views
warehouses={myState.warehouses}
allRamps={myState.allRamps}
currentWarehouse={myState.currentWarehouse}
pending={myState.pending}
error={myState.error}
/>
I have to use useRef to store current state additionally to be able to rerender the whole component.
My question is - is there any other solution without useRef? Where is the problem? Calback function doesn't work with useState hook?
Your pub/sub pattern does not inherit React's states. Whenever subscribe is triggered, and your callback function is initialized, that callback will not get any new values from myState.
To be able to use React's states, you can wrap refreshWarehouseCallback into another function like below
//`my state` is passed into the first function (the function wrapper)
//the inner function is your original function
const refreshWarehouseCallback =
(myState) => (eventName: string, content: any) => {
const { warehouseId } = myState;
//your other logic
};
And then you can add another useEffect to update subscribe after state changes (in this case, myState updates)
//a new state to store the updated pub/sub after every clean-up
const [pubSubToken, setPubSubToken] = useState();
useEffect(() => {
//clean up when your state updates
if (pubSubToken) {
pubsub.unsubscribe(pubSubToken);
}
const updatedPubSubToken = pubsub.subscribe(
"push:ttt.*",
refreshWarehouseCallback(myState) //execute the function wrapper to pass `myState` down to your original callback function
);
//update new pub/sub token
setPubSubToken(updatedPubSubToken);
return () => {
pubsub.unsubscribe(updatedPubSubToken);
};
//add `myState` as a dependency
}, [myState]);
//you can combine this with your previous useEffect
useEffect(() => {
const pushToken = push.subscribe("public/ttt/#");
return () => {
pubsub.unsubscribe(pushToken);
};
}, []);

useState function is not working in functional component

I want to change a state (filterConsultantId) with a useState function (setFilterConsultantId) after I trigger a normal function (handleConsultantChange) and I expect the state value is changed when I use the state in another normal function (getActiveLeads). But the state didn't change. Please see my React functional component below:
const TabActiveLeads = ({
...
}) => {
const [filterConsultantId, setFilterConsultantId] = useState('');
//after this arrow function triggered,
const handleConsultantChange = (event) => {
setFilterConsultantId(event.target.value); //and the filterConsultantId should be changed here
//this getActiveLeads function is called
getActiveLeads();
};
const getActiveLeads = () => {
// but the filterConsultantId here is not changed after it should be changed inside handleConsultantChange function
console.log(filterConsultantId);
};
};
export default TabActiveLeads;
I don't understand, why filterConsultantId is not changed inside the getActiveLeads function? Previously it should be changed by calling setFilterConsultantId inside the handleConsultantChange function.
Thanks for any help..
setFilterConsultantId is the asynchronous method, so you can't get the updated value of filterConsultantId right after setFilterConsultantId.
You should get it inside useEffect with adding a dependency filterConsultantId.
useEffect(() => {
console.log(filterConsultantId);
}, [filterConsultantId]);

is it possible to dispatch function when react component is unmount ? (React functional componet)

Hi I'm making some function which call api and save that value in the state, and then it should dispatch when user leave the component. so I tried to use react useEffect hooks as componentWillUnmount and dispatch some action with argument as state value.
but the problem is dispatch action is work but with empty string.. I think somehow state value is deleted and then dispatch function is executed.So is there's any way that I call function with state value, when user leave the component?
const [userCheck,setUserCheck]=React.useState('')
useEffect(() => {
const fetChItem='this is the function which calling api '
setUserCheck(fetChItem);
}, []);
useEffect(() => {
return () => {
dispatch(saveFetchValue(userCheck));
};
}, []);
Issue
This won't work because of how enclosures work with the useEffect callback. With the following
useEffect(() => {
return () => {
dispatch(saveFetchValue(userCheck));
};
}, []);
You have enclosed the initial userCheck state value ("") in the returned cleanup function.
Solution
Use a react ref and a second useEffect hook to "cache" the latest state.
const [userCheck, setUserCheck] = React.useState('');
const userCheckRef = React.useRef(userCheck); // ref to store state value
React.useEffect(() => {
userCheckRef.current = userCheck; // save userCheck state value to ref
}, [userCheck]);
...
useEffect(() => {
return () => {
dispatch(saveFetchValue(userCheckRef.current)); // pass current ref value
};
}, []);
Demo

React hook for component "componentWillUnmount" lifecycle method

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

Using React hook to run Mobx method before initial render of component

As the title suggests, i have my state inside a Mobx store. I have an async method (action) that fetches the data and stores it in a property inside the store, from where i will access it in the necessary component.
Problem is, currently the property will be undefined on the initial component render - resulting in an error in the component.
How do i make use of useEffect() so that it runs an async method once and only once - and before the initial component render, ensuring the state will be available for return()? Something like this:
const Workflow = () => {
const store = useContext(WorkflowContext)
useEffect(async () => {
await store.getWorkflow()
}, [])
...
You can check if the property in the store is undefined and return null from the component if that is the case.
Example
const Workflow = () => {
const store = useContext(WorkflowContext);
useEffect(() => {
store.getWorkflow();
}, []);
if (store.someProperty === undefined) {
return null;
}
return <div>{store.someProperty}</div>;
};

Resources