简体   繁体   中英

How to effectively initialise client register callback in react functional component or hook

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
    };
};
 

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]); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM