rsnext/docs/concepts/_server-side-and-client-side.md
Luis Alvarez D e3465615e4 New docs (#9301)
* Added the docs from Notion

* Updated the links from notion to relative links

* Added a routes manifest to the docs

* Removed the <br> after examples toggle

* Use the name of the section instead of Introduction

* Fixed spelling errors

* Optimize the content for Algolia

* Add a paragraph for `pageProps`

* Add welcome section

* Transpile -> Compile

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Test extra room between

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update getting-started.md

* Update manifest.json

* Update getting-started.md

* Update getting-started.md

* Add concepts section

* Update pages.md

* Update pages.md

* Add data fetching section

* Update pages.md

* See how a card looks like

* Undo card changes

* Added related section to getting-started

* Fixed wrong markdown syntax in the withRouter page

* Moved the server-side-and-client-side section

* Updated next-cli reference

* updated getInitialProps section

* Minor fixes

* Added more Related sections

* Add html to the related section in getting-started

* Use small for the card

* Use cards for all related sections

* Added src directory docs

* Added src directory to the manifest

* Add note about API routes in next export

* Add initial data fetching docs (private until new methods are released)

* Fix typos

* Improve wording

* Update getting-started.md

* Update getting-started.md

* Move advanced concepts to advanced section

* Hide server-side vs client-side

* Move AMP support

* Move typescript into one page

* Add routing concepts page

* Remove introduction page

* Update section on different route types

* Update routing.md

* Update routing.md

* Update routing.md

* Update routing.md

* Combine router injection pages

* Update pages.md

* Update routing.md

* Update using-link.md

* Update using-link.md

* Update typescript.md

* Move the API Routes typescript to basic features

* Added links to the typescript section

* Updated links to useRouter and withRouter

* Add singleLevel prop to manifest

* Added single page for router docs

* Updated description

* Updated the routes in the manifest

* Add data fetching section

* Update data-fetching.md

* Update data-fetching.md

* Update dynamic-routes.md

* Update manifest.json

* Only use the single router API page

* Moved the concepts pages

* Updated links

* Removed extra space

* Updated title for Router API

* Added a description with frontmatter

* Add open prop to the manifest

* Added datafetching section to API Reference

* Updated links to the getInitialProps reference

* Moved some sections to API

* Added next/head to API reference

* Added next/link to the API Reference

* Removed the populating-head section

* Updated links to the new next/link API

* Added link from dynamic-routes to next/link docs

* use a paragraph

* Added next/router API

* Added next/amp

* Updated the docs for next/amp

* Moved the AMP support folder

* Updated title

* Content updates

* Added more links to the data fetching section

* Added links from the API to introductions

* changing the router API

* Updates to the router API

* Updated the routing section

* life improvements

* Added shallow routing section

* Small fix

* Removed old routing sections

* Updated link to shallow routing

* Removed unrequired page

* Removed /pages

* Update data-fetching.md

* Add initial deployments section

* Update manifest.json

* Update introduction.md

* Update deployment doc

* Add static export section updates

* link ssg/ssr

* Update deployment.md

* Add syntax highlighting

Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
2019-12-23 16:07:38 +01:00

133 lines
4.2 KiB
Markdown

# Server-Side and Client-Side
When working with Next.js, we tend to write isomorphic code that can be rendered in both Node.js and the browser, to give you a better idea, take a look at the following example:
```jsx
function Page() {
return <h1>Hello World</h1>
}
export default Page
```
The above example is pretty basic, but it properly demonstrates what an isomorphic `page` looks like. The page can be prerendered with Node.js to static HTML, and it can also be rendered by the browser.
Now, what if the page tries to use a browser-only API?. Like so:
```jsx
function Page() {
return <h1>Hello World. Your user agent is: {navigator.userAgent}</h1>
}
export default Page
```
[`navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator) is only available in the `window` object, therefore Node.js doesn't have access to it, so your page would end up in a server-side error.
To work with code that only works in one side, read the sections below.
> [Dynamic imports](/docs/advanced-features/dynamic-import.md) can also help you handle code that only loads when required.
## Client-side only code
If you need access to APIs that only exist in the browser, like `window`, then `useEffect` is the recommended solution. Take a look at the following example:
```jsx
import { useState, useEffect } from 'react'
function Page() {
const [userAgent, setUserAgent] = useState()
useEffect(() => {
setUserAgent(navigator.userAgent)
}, [])
return <h1>Hello World. Your user agent is: {userAgent}</h1>
}
export default Page
```
Everything inside the function passed to `useEffect` will always run after the initial render, meaning it only runs in the browser.
You can achieve the same using [class components](https://reactjs.org/docs/react-component.html), as in the following example:
```jsx
import React from 'react'
class Page extends React.Component {
componentDidMount() {
this.setState({ userAgent: navigator.userAgent })
}
render() {
return <h1>Hello World. Your user agent is: {this.state.userAgent}</h1>
}
}
export default Page
```
`componentDidMount` will only execute in the browser, just like `useEffect`.
> In both cases, `userAgent` will be `undefined` in the first render, and once `useEffect` or `componentDidMount` are executed, it will change to the value of `navigator.userAgent`.
## Server-side only code
Following the `userAgent` example from above, we can make it always available to the page by adding [`getInitialProps`](/docs/api-reference/data-fetching/getInitialProps.md), like so:
```jsx
import { useState, useEffect } from 'react'
function Page({ userAgent }) {
return <h1>Hello World. Your user agent is: {userAgent}</h1>
}
Page.getInitialProps = ({ req }) => {
if (typeof window === 'undefined') {
return { userAgent: req.headers['user-agent'] }
} else {
return { userAgent: navigator.userAgent }
}
}
export default Page
```
The above example uses `req` to get the user agent in the server, and `navigator` if `getInitialProps` is executed in the browser.
> `typeof window` not only allows the page to differentiate between sides, but it also enables webpack's dead code elimination. We replace `typeof window` with a constant using webpack [DefinePlugin](https://webpack.js.org/plugins/define-plugin/).
Only the required code that passes the condition (`typeof window === 'undefined'`) will be included in the build. So the server-side build for the page's `getInitialProps` would look like:
```jsx
Page.getInitialProps = ({ req }) => {
return { userAgent: req.headers['user-agent'] }
}
```
And the client-side build:
```jsx
Page.getInitialProps = ({ req }) => {
return { userAgent: navigator.userAgent }
}
```
Thanks to dead code elimination, you could also import modules only for the required side, as in the following example:
```jsx
Page.getInitialProps = async ({ req }) => {
if (typeof window === 'undefined') {
const cookie = await import('cookie')
const cookies = cookie.parse(req.headers.cookie)
return { userAgent: req.headers['user-agent'], theme: cookies.theme }
} else {
const cookies = await import('js-cookie')
return { userAgent: navigator.userAgent, theme: cookies.get('theme') }
}
}
```
And same as before, each build will only include the code that passes the condition.