简体   繁体   中英

why checking for undefined from a function call causes SSR error, but not directly using `typeof` in react?

Can anyone please help explain this unexpected behavior?

I have a working useSessionStorage hook from https://typeofnan.dev/using-session-storage-in-react-with-hooks/ that looks like the following:

import { useState, useEffect } from 'react';

function getSessionStorageOrDefault(key, defaultValue) {
  if (typeof sessionStorage === 'undefined') {
    return defaultValue;
  }
  const stored = sessionStorage.getItem(key);
  if (!stored) {
    return defaultValue;
  }
  return JSON.parse(stored);
}

function useSessionStorage(key, defaultValue) {
  const [value, setValue] = useState(
    getSessionStorageOrDefault(key, defaultValue)
  );

  useEffect(() => {
    sessionStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

export default useSessionStorage;

Notice how I check to make sure sessionStorage is defined in order to make sure it works in SSR:

  if (typeof sessionStorage === 'undefined') {
    return defaultValue;
  }

Now when I try to replace typeof sessionStorage === 'undefined' with a call to a utility method called isUndefined , I get SSR error that sessionStorage is not defined .

Here is the isUndefined utility method

export function isUndefined(value) {
  return typeof value === 'undefined';
}

And here is the modified useSessionStorage hook that calls isUndefined and SSR no longer works:

import { useState, useEffect } from 'react';
import { isUndefined } from 'utils/lang';

function getSessionStorageOrDefault(key, defaultValue) {
  if (isUndefined(sessionStorage)) {
    return defaultValue;
  }
  const stored = sessionStorage.getItem(key);
  if (!stored) {
    return defaultValue;
  }
  return JSON.parse(stored);
}

function useSessionStorage(key, defaultValue) {
  const [value, setValue] = useState(
    getSessionStorageOrDefault(key, defaultValue)
  );

  useEffect(() => {
    sessionStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
}

export default useSessionStorage;

Why does typeof sessionStorage === 'undefined' work, but replacing it with isUndefined(sessionStorage) causes it to no longer work?

This is due to just a basic fact of javascript and all programming languages that I can think of off the top of my head. When you call isUndefined(sessionStorage) , you are attempting to pass the the memory location identified by an identifier called sessionStorage by value to the function isUndefined . In order to do that, the sessionStorage identifier needs to be looked up and its value read, which is of course impossible since it hasn't yet been declared , hence the error.

On the other hand, typeof is an operator . You aren't passing the value of sessionStorage to it, but rather asking it to look up that identifier's type. It just so happens that typeof 's behavior when it is passed an undeclared identifier is to return 'undefined' instead of throwing an error.

Finally, it's worth noting that a declared but as yet undefined variable in javascript has a default value of undefined , so you can pass it to a function.

Hopefully the following is clear:

function isUndefined(identifier) {
  return typeof identifier === "undefined"
}

let x = true
let y

isUndefined(x) // false
isUndefined(y) // true
isUndefined(z) // Uncaught ReferenceError: z is not defined

It might be clearer if the message was "z has not been declared," but hopefully you now understand what it's really telling you.

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