【问题标题】:How does Next JS server side rendering works when result hits client?当结果到达客户端时,Next JS 服务器端渲染如何工作?
【发布时间】:2020-07-27 18:02:29
【问题描述】:

我在 NextJS 应用程序中遇到问题。

_app.js 文件中,我实例化了一个Context(它又实例化了一个State

在我的页面ContextTest 我声明了一个getServerSideProps()

这会从 API 返回一些数据,这些数据会传递给 _app.js 并保存到 Context's state

到目前为止,我有我需要的数据。

然后它转到目标页面组件,该组件读取上下文的状态并设置一个变量。 组件成功输出我的变量,形式为

let userName = userState.username ? userState.username : 'Guest' 

当页面加载时,我检查请求中的 HTML,确实我有 userState.username 值。

但是浏览器中显示的 HTML 有Guest

有两点需要注意:

1) 服务器端按预期呈现 2)该应用程序在该页面的客户端中再次执行(那么为什么我要渲染应用程序服务器端呢?)。结果是这个页面没有getServerSideProps() 的结果,所以我的状态是空的,我在控制台中收到警告。 3) 浏览器中显示的 HTML 是客户端执行 React 应用程序的结果。 (为什么?)

__app.js

import React, {useContext} from "react";
import {UserContext} from "../lib/Context/UserContext"

export default function RankerApp({Component, pageProps}) {
    const [userState, setUserState] = useContext(UserContext)();
    const [listState, setListState] = useContext(ListContext)();

    if (pageProps.serverContext && pageProps.serverContext.user) {
        setUserState({...userState, ...pageProps.serverContext.user})
    }
    delete pageProps['serverContext'];

    return (
        <ListContext.Provider value={[listState, setListState]}>
            <UserContext.Provider value={[userState, setUserState]}>
                <Component {...pageProps} />
            </UserContext.Provider>
        </ListContext.Provider>
    );
}

pages/contextTest.js

import React, {useContext} from 'react';
import {UserContext} from "../lib/Context/UserContext";
import Link from "next/link";
import UserContextSeeder from "../lib/User/UserContextSeeder";

export default function ContextPage1(props) {

    let [userState, setUserState] = useContext(UserContext);

    const currentLoggedInUserData = userState.loggedInUserId ? userState.users[userState.loggedInUserId] : null;
    const currentLoggedInUserName = currentLoggedInUserData ? currentLoggedInUserData.userName : 'Guest';

    return (
        <div>
            <h1>Page 1</h1>
            <Link href="contextTest2">
                <a>Page 2</a>
            </Link>
            <h1>Current Logged In User: {currentLoggedInUserName}</h1>
        </div>
    );
}

export async function getServerSideProps(context) {
    let userContext = {};
    // await UserContextSeeder(context).then(context => {userContext = context}); commented for simplicty
    userContext = {loggedInUserId: 222, users: {222: {userName: "Jorge"}}; // suppose this is the result 
    return {
        props: {
            serverContext: {
                user: {...userContext}
            }
        },
    }
}

更多内容:https://github.com/zeit/next.js/discussions/11871

【问题讨论】:

    标签: javascript reactjs next.js server-side-rendering


    【解决方案1】:

    让我们考虑一个 NextJS 没有水合的世界。您已经从服务器构建了 DOM 并将其发送到客户端,客户端显示了 HTML,每个人都很高兴。现在 React 必须执行一个 useEffect ,这将触发 DOM 的一些变化,但是如果 React 没有 DOM,它会如何比较虚拟 DOM 过程?

    因此,即使我们已经在服务器上完成了,我们也需要在客户端上进行水合/渲染过程。服务器端渲染不是我们为浏览器节省一些工作的过程,它是我们确保内容尽早准备好供用户和机器人查看的方式。

    Josh Comeau 对his blog 有一个很好的解释。

    换一种说法,让我们看看这段代码:

    if (pageProps.serverContext && pageProps.serverContext.user) {
       setUserState({...userState, ...pageProps.serverContext.user})
    }
    delete pageProps['serverContext'];
    
    return ();
    

    这里称为side effect,在render 中执行。虽然这适用于普通 React,但在 StrictMode 中是禁止的,并且会在 Suspense 中中断(在正常情况下也可能中断)。所以我们把它移到useEffect

    useEffect(() => {
      if (pageProps.serverContext && pageProps.serverContext.user) {
       setUserState(prevUserState => ({...prevUserState, ...pageProps.serverContext.user}));
      }
    }, [])
    

    请注意,我没有删除 page 道具,因为我们不需要。 useEffect 仅在客户端上执行,因此其效果将仅在客户端上显示。如果您希望它们出现在第一次渲染中,则必须使用该道具来渲染用户名。示例:

    const [userState, setUserState] = useContext(UserContext)(props.serverContext ? props.serverContext.user : null);
    

    上下文挂钩:

    const initialState = {
        loggedInUserId: undefined,
        users: {}
    }
    
    const userContextUpdater = (initialUser) => {
        let [state, setState] = useState({
          ...initialState,
          users: initialUser || initialStateusers,
        })
        return [state, setState];
    }
    

    【讨论】:

    • 谢谢!所以你说我不能使用 useState 和 useContext() 在服务器端渲染中获取这些道具?
    • 你可以将 prop 设置为状态的初始值。但是由于客户端渲染,您还需要useEffect
    • 感谢您的回答和您在上面花费的时间,但只是我一直在阅读,无法理解为什么 NextJS 无法呈现某些内容

      {userName}

      使用一些数据(我已经工作过),然后将此数据公开为客户端的初始 React 数据?
    • 好的,我能够获取数据客户端并且没有错误! if (pageProps.serverContext &amp;&amp; pageProps.serverContext.user &amp;&amp; Object.keys(userState.users).length === 0 &amp;&amp; userState.users.constructor === Object) { setUserState({...userState, ...pageProps.serverContext.user}) } 基本上我是从getServerSideProps 中删除数据,所以它从未到达客户端HTML。我必须做额外的检查以确保它只改变一次状态。所以delete pageProps['serverContext']; 消失了
    • @JorgeeFG 这在render 中仍然是一个副作用,并且会长期咬你。你能告诉我你的UserContext文件里有什么吗?
    猜你喜欢
    • 2021-11-20
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-03-30
    • 2018-01-05
    • 2012-01-17
    • 1970-01-01
    相关资源
    最近更新 更多