在React中,如何检测我的组件是从客户端还是服务器呈现?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在React中,如何检测我的组件是从客户端还是服务器呈现?相关的知识,希望对你有一定的参考价值。
我正在构建一个同构应用程序,但我正在使用仅在客户端上呈现的第三方组件。所以,特别是对于这个组件,我只需要在客户端渲染时才渲染它。
如何检测我是在客户端还是在服务器上?我正在寻找像isClient()
或isServer()
这样的东西。
在内部,React为此使用了一个名为ExecutionEnvironment
的实用程序。它实现了一些有用的属性,如canUseDOM
和canUseEventListeners
。解决方案基本上就是here的建议。
canUseDOM
的实施
var canUseDOM = !!(
(typeof window !== 'undefined' &&
window.document && window.document.createElement)
);
我在我的应用程序中使用这个
var ExecutionEnvironment = require('react/node_modules/fbjs/lib/ExecutionEnvironment');
...
render() {
<div>{ ExecutionEnvironment.canUseDOM ? this.renderMyComponent() : null }</div>
}
编辑这是一个未记录的功能,不应直接使用。它的位置可能会因版本而异。我通过展示Facebook团队内部使用的内容,将此作为一种说法“这是你能做的最好”的方式。您可能希望将此代码(它很小)复制到您自己的项目中,因此您不必担心跟踪其版本之间的位置或潜在的重大更改。
另一个编辑有人为此代码创建了npm package。我建议使用它。
npm install exenv --save
两件可能相关的事情:
许多项目使用一些约定来设置全局SERVER或CLIENT布尔值,因此所有代码都可以根据它进行切换。在您的服务器包中,设置一些全局,like in this project
global.__SERVER__ = true;
在您的客户端包中,将一些全局客户端设置为true,您可以通过单向with Webpack's DefinePlugin实现
new webpack.DefinePlugin({
__CLIENT__: true
})
使用上述方法,您可以在willMount或render中基于该变量进行切换,以在服务器上执行一项操作,在客户端上执行另一项操作。
这里可能有用的第二件事是componentDidMount
只在客户端运行,但不在服务器上运行。
您可以使用reacts lifecyle事件(例如:componentDidMount
)来检测服务器/客户端呈现。
例子
As Hook
import { useState, useEffect } from 'react'
function useIsServer () {
const [isServer, setIsServer] = useState(true)
useEffect(() => {
setIsServer(false)
}, [])
return isServer
}
用法
见下文(功能组件)
As Functional Component
import useIsServer from './above'
function ServerOnly ({ children = null, onClient = null }) {
const isServer = useIsServer()
return isServer
? children
: onClient
}
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
As Class Component
class ServerOnly extends React.Component {
constructor (props) {
super(props)
this.state = {
isServer: true
}
}
componentDidMount() {
this.setState({
isServer: false
})
}
render () {
const { isServer } = this.state
const { children, onClient } = this.props
return isServer
? children
: onClient
}
}
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
您还可以使用componentDidMount()
,因为当页面是服务器端呈现时,不会运行此生命周期方法。
在服务器元素层次结构的最顶层,可以添加一个ServerContext
,如下所示:
class ServerContext extends React.Component {
getChildContext() { return { isServer: true }; }
render() { return React.Children.only(this.props.children); }
}
ServerContext.propTypes = {
children: React.PropTypes.node.isRequired,
};
ServerContext.childContextTypes = {
isServer: React.PropTypes.bool.isRequired,
};
// Create our React application element.
const reactAppElement = (
<ServerContext>
<CodeSplitProvider context={codeSplitContext}>
<ServerRouter location={request.url} context={reactRouterContext}>
<DemoApp />
</ServerRouter>
</CodeSplitProvider>
</ServerContext>
);
这样做,应该可以从上下文中读取isServer,如下所示:
const Layout = (_, { isServer }) => (
// render stuff here
);
您可以在exenv
包的帮助下创建一个有用的实用程序。
import { canUseDOM } from 'exenv';
export function onClient(fn: (..._args: any[]) => any): (..._args: any[]) => any {
if (canUseDOM) {
return fn;
}
if (process.env.NODE_ENV === 'development') {
console.log(`Called ${fn.name} on client side only`);
}
return (): void => {};
}
并像这样使用它
function my_function_for_browser_only(arg1: number, arg2: string) {}
onClient(my_function_for_browser_only)(123, "Hi !");
并且只在客户端调用该函数,如果设置NODE_ENV=development
,它将在服务器端登录,在客户端调用此函数
(这是打字稿,删除JS的类型:))
你也可以使用use-ssr
React钩子
import useSSR from 'use-ssr'
const App = () => {
var { isBrowser, isServer } = useSSR()
// Want array destructuring? You can do that too!
var [isBrowser, isServer] = useSSR()
/*
* In your browser's chrome devtools console you should see
* > IS BROWSER: 以上是关于在React中,如何检测我的组件是从客户端还是服务器呈现?的主要内容,如果未能解决你的问题,请参考以下文章
在 PHP 中,如何检测执行是从 CLI 模式还是通过浏览器? [复制]