Javascript 在React中,如何检测组件是从客户端还是从服务器渲染?
我正在构建一个同构的应用程序,但我使用的是只在客户端呈现的第三方组件。因此,特别是对于这个组件,我只需要在客户端渲染时渲染它Javascript 在React中,如何检测组件是从客户端还是从服务器渲染?,javascript,node.js,reactjs,Javascript,Node.js,Reactjs,我正在构建一个同构的应用程序,但我使用的是只在客户端呈现的第三方组件。因此,特别是对于这个组件,我只需要在客户端渲染时渲染它 如何检测我是在客户端还是在服务器上?我正在寻找类似于isClient()或isServer()的东西。在内部,React使用一个名为ExecutionEnvironment的实用程序来实现这一点。它实现了一些有用的属性,如canUseDOM和canuseventlisteners。不过,解决方案基本上就是我们所建议的 canUseDOM的实现 var canUseDOM
如何检测我是在客户端还是在服务器上?我正在寻找类似于
isClient()
或isServer()
的东西。在内部,React使用一个名为ExecutionEnvironment
的实用程序来实现这一点。它实现了一些有用的属性,如canUseDOM
和canuseventlisteners
。不过,解决方案基本上就是我们所建议的
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>
}
function my_function_for_browser_only(arg1: number, arg2: string) {}
onClient(my_function_for_browser_only)(123, "Hi !");
有两件事可能是相关的: 许多项目使用某种约定,在这种约定中,它们设置了一个全局服务器或客户端布尔值,以便您的所有代码都可以基于它进行切换。在服务器包中,设置一些全局 在您的客户机包中,将某个全局客户机设置为true,这可以通过一种方式实现 使用上述方法,您可以在willMount或render中关闭该变量,在服务器上执行一项操作,在客户端执行另一项操作
第二件可能有用的事情是
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>
);
您还可以使用
componentDidMount()
,因为在服务器端呈现页面时不会运行此生命周期方法。您可以在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 => {};
}
像这样使用它
var ExecutionEnvironment = require('react/node_modules/fbjs/lib/ExecutionEnvironment');
...
render() {
<div>{ ExecutionEnvironment.canUseDOM ? this.renderMyComponent() : null }</div>
}
function my_function_for_browser_only(arg1: number, arg2: string) {}
onClient(my_function_for_browser_only)(123, "Hi !");
如果您设置NODE\u ENV=development
(这是typescript,删除JS的类型:)您可以使用reacts事件(例如:componentDidMount
)来检测服务器/客户端呈现
例子
作为钩子
从'react'导入{useState,useffect}
函数useIsServer(){
常量[isServer,setIsServer]=useState(真)
useffect(()=>{
setIsServer(错误)
}, [])
返回isServer
}
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
见下文(功能组件)
作为功能部件
从“/以上”导入UseiServer
函数ServerOnly({children=null,onClient=null}){
const isServer=useIsServer()
返回isServer
儿童
:onClient
}
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
用法
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
<ServerOnly
children='This String was rendered on the server'
onClient='This String was rendered on the client'
/>
您也可以使用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: You can check if global window
variable is defined or not.
as in browser it should always be defined.
var isBrowser = window!==undefined
从“使用ssr”导入使用ssr
常量应用=()=>{
var{isBrowser,isServer}=useSSR()
//想要阵列分解?你也可以!
var[isBrowser,isServer]=useSSR()
/*
*在浏览器的ChromeDevTools控制台中,您应该可以看到
*>IS BROWSER:您可以检查是否定义了全局窗口
变量。
和在浏览器中一样,应该始终定义它
if (typeof window === "undefined") { //client side code }
如果没有typeof
,你会出现一个错误。你不能检查一些全局的,比如window
,或者process
?类似的:谢谢@elclars和@zerkms。这是我想到的第一件事,但是我尝试了if(windows){/code>,而实际上我应该做typeof window
ReactDOM.render(,document.getElementById('root'),()=>console.log('render!))
你能回顾一下我的答案吗?如果有什么问题,请更正。数组解构对我不起作用。我使用了对象解构。只是好奇,为什么开始时!!将值转换为布尔值,以确保返回true
或false
,而不是potentiallyundefined
。您可以将上面的!!
替换为Boolean
,并获得相同的结果。在这里,我们使用&
运算符,我看不到最终返回未定义的路径,或者返回true或false以外的其他值。我错了吗?如果window.document
存在,但没有createElement
方法,这将返回未定义的。如果它确实有createElement
方法,它将返回该方法,也称为函数。要测试这一点,您可以复制并粘贴到javascript控制台中(不带!!
),并查看它是否返回函数