Javascript 在 React 中,如何检测我的组件是从客户端渲染还是从服务器渲染?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32216383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
In React, how do I detect if my component is rendering from the client or the server?
提问by André Pena
I'm building a isomorphic application, but I'm using a third-party component that only renders on the client. So, particularly for this component, I need to only render it when I'm rendering in the client.
我正在构建一个同构应用程序,但我使用的是仅在客户端上呈现的第三方组件。所以,特别是对于这个组件,我只需要在客户端渲染时渲染它。
How do I detect if I'm at the client or at the server? I'm looking for something like isClient()
or isServer()
.
如何检测我是在客户端还是在服务器?我正在寻找类似isClient()
或的东西isServer()
。
回答by Charlie Martin
Internally, React uses a utility called ExecutionEnvironment
for this. It implements a few useful properties like canUseDOM
and canUseEventListeners
. The solution is essentially just what's suggested herethough.
在内部,React 使用了一个ExecutionEnvironment
为此调用的实用程序。它实现了一些有用的属性,例如canUseDOM
和canUseEventListeners
。解决方案基本上就是这里所建议的。
The implementation of canUseDOM
实施 canUseDOM
var canUseDOM = !!(
(typeof window !== 'undefined' &&
window.document && window.document.createElement)
);
I use this in my application like this
我像这样在我的应用程序中使用它
var ExecutionEnvironment = require('react/node_modules/fbjs/lib/ExecutionEnvironment');
...
render() {
<div>{ ExecutionEnvironment.canUseDOM ? this.renderMyComponent() : null }</div>
}
EDITThis is an undocumented feature that shouldn't be used directly. Its location will likely change from version to version. I shared this as a way of saying "this is the best you can do" by showing what the Facebook team uses internally. You may want to copy this code (it's tiny) into your own project, so you don't have to worry about keeping up with its location from version to version or potential breaking changes.
编辑这是一个不应直接使用的未记录功能。它的位置可能会因版本而异。我通过展示 Facebook 团队内部使用的内容来分享这一点,以此表达“这是你能做的最好的事情”。您可能希望将此代码(它很小)复制到您自己的项目中,这样您就不必担心在不同版本之间保持其位置或潜在的破坏性更改。
ANOTHER EDITSomeone created an npm packagefor this code. I suggest using that.
另一个编辑有人为此代码创建了一个npm 包。我建议使用那个。
npm install exenv --save
回答by Andy Ray
Two things that may be relevant:
可能相关的两件事:
Many projects use some convention where they set a global SERVER or CLIENT boolean so all your code can switch based off it. In your server bundle, set some global, like in this project
许多项目使用一些约定来设置全局 SERVER 或 CLIENT 布尔值,因此您的所有代码都可以基于它进行切换。在你的服务器包中,设置一些全局,就像在这个项目中一样
global.__SERVER__ = true;
And in your client bundle, set some global client to true, which you can achieve one way with Webpack's DefinePlugin
并在您的客户端包中,将一些全局客户端设置为 true,您可以使用 Webpack 的 DefinePlugin 的一种方式来实现
new webpack.DefinePlugin({
__CLIENT__: true
})
With the above approach, you could switch based off that variable in willMount, or render, to do one thing on the server, and another on the client.
使用上述方法,您可以在 willMount 或 render 中关闭该变量,以便在服务器上做一件事,在客户端做另一件事。
The second thing that may be helpful here is componentDidMount
only runs on the client, but not on the server.
在这里可能有用的第二件事是componentDidMount
仅在客户端上运行,而不是在服务器上运行。
回答by HaNdTriX
You can use reacts lifecyleevents (e.g.: componentDidMount
) to detect server/client side rendering.
您可以使用 reacts lifecyle事件(例如:)componentDidMount
来检测服务器/客户端渲染。
Examples
例子
As Hook
作为钩
import { useState, useEffect } from 'react'
function useIsServer () {
const [isServer, setIsServer] = useState(true)
useEffect(() => {
setIsServer(false)
}, [])
return isServer
}
Usage
用法
See below (Functional Component)
见下文(功能组件)
As Functional Component
作为功能组件
import useIsServer from './above'
function ServerOnly ({ children = null, onClient = null }) {
const isServer = useIsServer()
return isServer
? children
: onClient
}
Usage
用法
<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
}
}
Usage
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
回答by JoeTidee
You can also use componentDidMount()
, as this lifecycle method is not run when the page is server-side rendered.
您也可以使用componentDidMount()
,因为在服务器端呈现页面时不会运行此生命周期方法。
回答by Alex Cory
You could also just use the use-ssr
React hook
你也可以只使用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:
* > IS SERVER:
*
* AND, in your terminal where your server is running you should see
* > IS BROWSER:
* > IS SERVER:
*/
console.log('IS BROWSER: ', isBrowser ? '' : '')
console.log('IS SERVER: ', isServer ? '' : '')
return (
<>
Is in browser? {isBrowser ? '' : ''}
<br />
Is on server? {isServer ? '' : ''}
</>
)
}
回答by Ramesh Pareek
You can check if global window
variable is defined or not.
as in browser it should always be defined.
您可以检查是否window
定义了全局变量。就像在浏览器中一样,它应该始终被定义。
var isBrowser = window!==undefined
回答by Iulian Rotaru
You can create one useful utility with the help of the exenv
package.
您可以在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 => {};
}
And use it like this
并像这样使用它
function my_function_for_browser_only(arg1: number, arg2: string) {}
onClient(my_function_for_browser_only)(123, "Hi !");
And the function will only be called on client side, and it will log on server side that this function has been called on client side if you set NODE_ENV=development
并且该函数只会在客户端调用,如果您设置,它会在服务器端登录该函数已在客户端调用 NODE_ENV=development
(It's typescript, remove types for JS :) )
(这是打字稿,删除 JS 的类型 :) )
回答by JoeTidee
At the topmost level of the server Element hierarchy, one could add a ServerContext
such as this:
在服务器元素层次结构的最顶层,可以添加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>
);
Doing so, it should be possible to read the isServer from the context like this:
这样做,应该可以像这样从上下文中读取 isServer :
const Layout = (_, { isServer }) => (
// render stuff here
);