Hi guys I am trining use factory class in react functional component. I need initialise base on components props and do it in first render or when props change.
AS thats why I created instance and store it ref in useEffect with array that dependent on props to get always new instance when prop changed.
But when I do it a need some special state to force component update.
I am still thinking that there is better and cleaner way how to do it. What is strange is the dummy state to force component to update.
So my code that looks is working looks like this:
export const useClientLoader = (props: IClientLoaderProps) => {
const { backend, workspace, filter } = props;
const [,setInvalidate] = useState(0);
const [initStatus,setInitStatus] = useState<status>("pending");
const loaderRef = useRef<IClientLoader>();
const invalidate = ()=>{
// force component update via changing state
setInvalidate(i=>i 1);
}
useEffect(() => {
// init client instance
loaderRef.current = newClientHandler(backend, workspace, filter);
// update ref not update state and re-render component
// so i do force to update by dummy state update
invalidate();
}, [backend, workspace, filter]); // I need new instance when props changed
const onInitSuccess = () => {
setInitStatus("success");
};
// I need current pointer to client instance
const loader = loaderRef.current;
useEffect(() => {
if (loader) {
// subscribe callback
const onInitSuccessUnsubscribe = loader.onInitSuccess(onInitSuccess);
// init client and do magic on backend and wait for result via callback
loader.init();
return () => {
// Unsubscribe callback
onInitSuccessUnsubscribe();
};
}
}, [loader]); // I will do change just when I have new client instance
return {
initStatus:initStatus,
getUser: loader?.getUser
};
};
Thanks very much for your hints.
CodePudding user response:
I guess you can achieve it with just one useEffect, no need to split on two and then to be forced to use workaround in order to trigger rerender. Like this:
const loaderRef = useRef<IClientLoader>();
const onInitSuccess = useCallback(() => {
setInitStatus("success");
}, []);
useEffect(() => {
loaderRef.current = newClientHandler(backend, workspace, filter);
const onInitSuccessUnsubscribe = loaderRef.current.onInitSuccess(onInitSuccess);
loaderRef.current.init();
return () => {
// Unsubscribe callback
onInitSuccessUnsubscribe();
};
}, [backend, workspace, filter, onInitSuccess]);