0

can you help me cancel the subscriptions in this case?

const Main = () => {
    const [ toggle, setToggle] = useState(false)

    return (
        <React.Fragment>
            {toggle && <Child />}
            <button onClick={() => setShow(prevState => !prevState)}>toggle</button>
        </React.Fragment>
    )
}

const Child = () => {
    const [ success, setSuccess] = useState(false)
    const createUser = () => {
        return createUserInTheDatabase()
            .then(() => setSuccess(true))
    }

    return (
        <React.Fragment>
            {success && <p>user created<p>}
            <button onClick={() => createUser()}>create user</button>
        <React.Fragment>
    )
}

I get the error when I click the toggle button and the createUser function in the Child component didn´t finish the execution. not exactly what to do in the useEffect cleanup function.

handsome
  • 2,335
  • 7
  • 45
  • 73
  • Can you please update question with a [Minimal, Complete, and Reproducible](https://stackoverflow.com/help/minimal-reproducible-example) example? The child component appears to be missing some definitions. What have you tried? – Drew Reese Apr 29 '20 at 05:46
  • Not sure what you are aiming for, but i guess you want to cancel the xhr request when you click on toggle button. Does this answer your question https://stackoverflow.com/a/47250621/2861108 ? – MjZac Apr 29 '20 at 06:04

2 Answers2

1

If you doesn't want to render anything after the component is unmounted then you can use this code sample to achieve that.

I have created _IsMounted variable and set it to false. When useEffect is called that means component are mounted, so it set _IsMounted to true.

When the component are unmounted from screen the react calls return method from useEffect and it set _IsMounted to false. So when you try to update state when there is no component mounted, it will not leads to crash.

This will not cancel subscription or async code but they will not effect the application or leads to any error.

const Main = () => {
    var _IsMounted = false;
    const [ toggle, setToggle] = useState(false)

    return (
        <React.Fragment>
            {toggle && <Child />}
            <button onClick={() => setShow(prevState => !prevState)}>toggle</button>
        </React.Fragment>
    )
}

const Child = () => {
    const createUser () => {
        return createUserInTheDatabase()
            .then(() => {
                       if(_IsMounted)
                        {
                             setSuccess(true);
                         }
                     })
    }
}
useEffect(() => {
    _IsMounted = true;

     return(){
         _isMounted = false; 
     }
},[])
return (
     <React.Fragment>
        {success && <p>user created<p>}
            <button onClick={() => createUser()}>create user</button>
     <React.Fragment>
    );
}

Ferin Patel
  • 3,424
  • 2
  • 17
  • 49
  • cool wasn´t sure about to add isMounted && setSuccess(true) or... isMounted && createUserInTheDatabase(...) thanks for your help. – handsome Apr 29 '20 at 06:04
  • I´m getting this warning. Assignments to the '_isMounted' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect – handsome Apr 29 '20 at 17:52
0

Login with api post:

STOP ONE:

const [unmounted, setUnmounted] = useState(true);
  const [login, setIsLogin] = useState(true);
  useEffect(() => {
    if (login) setUnmounted(true); // this is not importent
    return () => {
      setIsLogin(false);
    };
  }, [login]);

Step Two:

try {
  const req = await axios.post(`${URL_SERVER}/login`, {
    email,
    password,
  });
  if (unmounted) {
    setIsLogin(false);
    setUnmounted(false);

///....

}
Ahmad Tech
  • 21
  • 1
  • 1