Reputation: 2220
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?
Upvotes: 0
Views: 593
Reputation: 15540
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);
};
}, []);
Upvotes: 1