0

I am having an issue where it seems my state variable is being overwritten by the default/initial value I set when calling useState(). I have const [token, setToken] = useState(""). I pass in the setToken function to my Login component, and when I log in I update the token via the setToken function.

In my App.js I only want to render the Login component if the token is not set, otherwise, I redirect to a Post.js component. Once I log in my token is being set and I am being redirected to my Posts.js page, the problem is if I refresh the page the token is overwritten again to the initial value and I'm not sure why that is.

My understanding is that useState() is only called on the initial render, otherwise the state is obtained from whatever is stored in state which since I called the setToken function, should be the state with the token, not an empty string.

What am I missing?

App.js

function App() {
  const [errors, setErrors] = useState([]);
  const [token, setToken] = useState("");

  
  console.log('token', token)
  return (
    <Fragment>
      <Router>
        <Navbar />
        <Route exact path="/" component={Landing} />
        <Container>
          {!errors.length ? <></> : <Alerts errors={errors} handleError={setErrors}/> }
          <Switch>
            <Route 
              exact path="/login" 
              render={ token ? (props) => <Redirect push to="/posts" {...props} /> : (props) => (<Login error={setErrors} isLoggedIn={setToken} {...props} />)}
            />
            <Route exact path="/posts" 
            render={token ? (props) => <Posts token={token} {...props} /> : (props) => <Redirect push to="/login" {...props} />} />
          </Switch>
        </Container>
      </Router>
    </Fragment>
    
  );
}

Pertinent section of Landing.js

const handleSubmit = async (e) => {
    e.preventDefault();
    const res = await login(email, password);

    if(res.status !== 200){
      props.error(res.data.errors);
    }else{
      props.error([])
      props.isLoggedIn(res.data.token)
    }

  }

UPDATE: I did figure out how to do what I wanted to do, by storing my token in local storage. In my App.js I'm doing this now

function App() {
  const [errors, setErrors] = useState([]);
  const [token, setToken] = useState(null);

  useEffect(() => {
    setToken(window.localStorage.getItem("token"));
  })

This is not overwriting my token state as it was initially, so it's doing what I want, but I'm still wondering what I was doing wrong in my original implementation?

pdad04
  • 75
  • 1
  • 7
  • Should store it in a secure cookie. [Localstorage](https://stackoverflow.com/questions/3718349/html5-localstorage-security) isn't secure – Tony May 10 '21 at 00:13

1 Answers1

0

when you refresh the page your app runs from the beginning. If you don't want to lose your token on page refresh you should save/retrieve your to/from localStorage.

get2dachoppa
  • 161
  • 3
  • Thanks. Yeah, I knew it was something super basic. I'm just giving hooks a go and so I overcomplicated something really basic. – pdad04 May 10 '21 at 00:35
  • @pdad04 Your routes can be simplified. Switch renders only the first Route specified for the current path, so you need 2 routes, one for /login and one for posts. try this: } /> {token && } />} – get2dachoppa May 10 '21 at 10:39