Search code examples
reactjsreact-hooksuse-effect

Child component not re-rendering even though parent state is updated using hooks


I have a functional component App with a useEffect hook and I'm trying to get the <Redirect> child component to re-render on a state change, specifically the call to setUserInSystem, which should update userInSystem, which is explicitly referenced in the render method. However the component does not re-render when userInSystem changes and I can't figure out why. (Note: both async functions getUserInfo and getUserByWorkEmail are working as expected and retrieving correct data.)

const App = (props) => {
  const { authState, authData } = props;
  const [signedIn, setSignedIn] = useState(false);
  const [userInfo, setUserInfo] = useState(undefined);
  const [userInSystem, setUserInSystem] = useState(false);

  useEffect(() => {
    setSignedIn(!(authState !== 'signedIn'));
    const fetchUser = async () => {
      const data = await getUserInfo();
      const userFound = await getUserByWorkEmail(data);
      setUserInSystem(userFound);
      setUserInfo(data);
    };
    if (authState === 'signedIn') {
      fetchUser();
    }
  }, [authState]);


return (
    <div>
        <BrowserRouter>
            <Switch>
            <Redirect
                exact={true}
                path="/"
                to={userInSystem ? '/dashboard' : '/unverified'}
            />
            </Switch>
        </BrowserRouter>
      </LayoutProvider>
    </div>
  );
};

Solution

  • Create a new hook and envelope the Redirect with a condition that is mutated every fetch:

    const [loading, setLoading] = useState(true);
    

    In the fetch setLoading to false after the fetch is resolved.

    const fetchUser = async () => {
          setLoading(true);
          const data = await getUserInfo();
          const userFound = await getUserByWorkEmail(data);
          setUserInSystem(userFound);
          setUserInfo(data);
          setLoading(false);
        };
    

    Then in the return:

    <Switch>
    { !loading ? <Redirect
                exact={true}
                path="/"
                to={userInSystem ? '/dashboard' : '/unverified'}
            /> 
            : <div>Loading....</div> 
    }
    </Switch>