ReactDOM.hydrate() 会在客户端触发生命周期方法吗?

IT技术 reactjs react-dom react-dom-server
2021-05-18 05:33:02

React 16 文档关于ReactDOM.hydrate()

与 render() 相同,但用于混合容器,其 HTML 内容由 ReactDOMServer 呈现。React 将尝试将事件侦听器附加到现有标记。

  1. 会不会ReactDOM.hydrate()也触发客户端上的生命周期方法,例如componentWillMount()componentDidMount()在最初的呈现?

  2. render()水化期间在客户端上调用方法吗?我想不会,因为这之间的区别ReactDOM.render()ReactDOM.hydrate()

如果render方法不会在客户端被调用,我们不会期望componentDidMount()生命周期方法被触发。

如果客户端没有调用任何生命周期方法,我们如何知道 React 何时完成渲染。我想callback在以下语法中:

ReactDOM.水合物(元素,容器[,回调])

我想了解当 React “尝试将事件侦听器附加到现有标记”时,是否有可用的生命周期方法/钩子(可以对应用程序进行更多控制)。

3个回答
  1. 由于ReactDOM.hydrate是(也应该)呼吁在客户端上,然后它应该运行componentDidMount在服务器上呈现时已经调用了componentWillMountcomponentDidMount不在服务器上运行,因此当您调用 hydrate 时,应用程序会运行该事件。

  2. 将水合物视为一种不同的渲染方法。它确实呈现但不以相同的方式呈现。它会查找您的服务器呈现的 React 和您的客户端 React 之间的不匹配。它不会再次渲染所有内容。

React 期望渲染的内容在服务器和客户端之间是相同的。它可以修补文本内容中的差异(例如时间戳),但您应该将不匹配视为错误并修复它们

但是,您可能想做一些疯狂的事情,例如在客户端渲染完全不同的东西(与在服务器上渲染的东西相比)。为此请注意本段

如果您有意需要在服务器和客户端上渲染不同的东西,您可以进行两次渲染。在客户端呈现不同内容的组件可以读取像 this.state.isClient 这样的状态变量,您可以在 componentDidMount() 中将其设置为 true。通过这种方式,初始渲染通道将渲染与服务器相同的内容,避免不匹配,但附加通道将在水合后立即同步发生。请注意,这种方法会使您的组件变慢,因为它们必须渲染两次,因此请谨慎使用。

正如你所看到的,它进行了渲染过程。如果没有不匹配,React 会为此进行优化。

我希望它澄清了。我根据 React SSR 的经验和阅读文档的基本理解发言。

服务器和客户端之间呈现的元素可能不同,因为最初元素在内存中的服务器上呈现为文本,因此它们没有被挂载。当内容被移动到客户端时,它可以被重新附加到react,通过hydrate它是假的“渲染”来连接其余的react功能,比如事件。

为了告诉它什么时候水合,这是我发现的互联网上的一篇文章,它清楚地说明了上述合理性。https://dev.to/merri/understanding-react-ssr-spa-hydration-1hcf?signin=true

const HydrateContext = createContext('hydrated')

export function useIsHydrated() {
    return useContext(HydrateContext)
}

export function IsHydratedProvider({ children }) {
    const [isHydrated, setIsHydrated] = useState(false)
    useEffect(() => {
        setIsHydrated(true)
    }, [])
    return (
        <HydrateContext.Provider value={isHydrated}>
            {children}
        </HydrateContext.Provider>
    )
}

要使用它,

function MyComponent() {
    const isHydrated = useIsHydrated()
    return !isHydrated ? 'Initial render' : 'SPA mode'
}

function App() {
    return (
        <IsHydratedProvider>
            <MyComponent />
        </IsHydratedProvider>
    )
}

在我看来,任何渲染的组件都会从服务器传送到客户端。

ps 这是另一篇关于挂载后第二次渲染的文章,https://medium.com/swlh/how-to-use-useeffect-on-server-side-654932c51b13

我阅读了ReactDOM.hydrateTypeScript 系统中的类型

(
  element: SFCElement<any> | Array<SFCElement<any>>,
  container: Container| null,
  callback?: () => void
): void;

以及上述声明的示例:

ReactDOM.hydrate(
  <App />, // element
  document.getElementById('root'), // container
  () => { // callback

    /* do what you want after hydration */
  }
);