尝试从无状态React组件中的localStorage获取数据时出现NodeInvocationException

时间:2018-06-15 16:32:28

标签: asp.net reactjs react-router typescript-typings serverside-rendering

我已经实现了我的应用布局:

const Layout: React.SFC<IDefaultProps> = props => {
  const { component: Component, ...rest } = props;
  const logged = userServices.getUserLocalStorage();
  return (
    <Route
      {...rest}
      render={matchProps =>
        logged != null ? (
          <div className="container-fluid">
            <NavMenuLogged {...matchProps} />                
            <div className="row wu-content">
              <Component {...matchProps} />
            </div>                
            <Footer />
          </div>
        ) : (
          <Redirect to="/" />
        )
      }
    />
  );
};

希望在localStorage中保存用户的登录信息,并从那里,能够将用户重定向到登录;但我发现我无法访问SFC组件中的localStorage。有人有解决方案吗? (优雅,或不......)

这是getUserLocalStorage()函数:

export function getUserLocalStorage(){
    let user:Utils.User = JSON.parse(localStorage.getItem("user") || '{}');
    return user;
}

这是我得到的错误:

An unhandled exception occurred while processing the request.
NodeInvocationException: localStorage is not defined
ReferenceError: localStorage is not defined
at Object.getUserLocalStorage [as b] (E:\Trabajo\...\ClientApp\dist\main-server.js:9138:27)
at Layout (E:\...\ClientApp\dist\main-server.js:38836:102)
at ReactCompositeComponentWrapper._constructComponentWithoutOwner (E:\...\ClientApp\dist\vendor.js:43899:14)
at ReactCompositeComponentWrapper._constructComponent (E:\...\ClientApp\dist\vendor.js:43875:19)
at ReactCompositeComponentWrapper.mountComponent (E:\...\ClientApp\dist\vendor.js:43778:21)
at Object.mountComponent (E:\...\ClientApp\dist\vendor.js:11753:35)
at ReactCompositeComponentWrapper.performInitialMount (E:\...\ClientApp\dist\vendor.js:43961:34)
at ReactCompositeComponentWrapper.mountComponent (E:\Trabajo\...\ClientApp\dist\vendor.js:43848:21)
at Object.mountComponent (E:\...\ClientApp\dist\vendor.js:11753:35)
at ReactDOMComponent.mountChildren (E:\...\ClientApp\dist\vendor.js:47391:44)

2 个答案:

答案 0 :(得分:1)

由于错误出现在服务器上,因此在服务器端呈现阶段,很可能是由于Node环境中缺少localStorage。 Node中没有这样的东西,它是特定于浏览器的API。因此该函数会伪装ReferenceError(也许是因为它的ASP.NET,但我不确定)。

我认为无论如何都无法在服务器端呈现步骤中检索用户信息,并且该特定情况的用户数据仅存储在用户的浏览器中,存储在本地存储器中。在这种情况下,检查localStorage是否存在可能是有意义的,如果不存在,可以回退到默认值:

export function getUserLocalStorage(){
    if (typeof localStorage === 'undefined') {
        // will safely return if localStorage is not defined
        return {};
    }

    let user:Utils.User = JSON.parse(localStorage.getItem("user") || '{}');

    return user;
}

typeof •适用于之前未定义的任何,偶数变量或引用。检查范围内是否存在某个引用是最安全的操作。

比较
if (localStorage) {
    // will throw ReferenceError is localStorage is not defined
}

由于您可能不希望此时进行客户端/服务器代码拆分,因此typeof支持的检查可能是最佳选择。这样,您可以确保以下代码仅在localStorage引用可用的环境中运行(在大多数情况下,在浏览器的全局范围内)。您可能已经应用的相同做法是检查是否定义了window

希望它有所帮助!

答案 1 :(得分:0)

这与您设置应用程序的方式有关,当您致电localStorage时,它必须在客户端发生,而不是在服务器端发生。作为节点,没有本地存储。

我会试试这个: 将其更改为类组件而不是使用功能组件,然后执行

componentDidMount(){
    console.log(localStorage) // or whatever you need to do here.
} 

如果您不想删除SFC,可以创建自己的HOC,或使用recompose之类的库。以下是使用重构的代码段:

const SFCWithLifeCycleHook = lifecycle({
  componentDidMount() {
    console.log(localStorage) //do something here...
  }
})(SFC);