【问题标题】:Will ReactDOM.hydrate() trigger lifecycle methods on the client?ReactDOM.hydrate() 会在客户端触发生命周期方法吗?
【发布时间】:2018-04-22 11:55:57
【问题描述】:

来自React 16 docs关于ReactDOM.hydrate()

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

  1. ReactDOM.hydrate() 是否还会在初始渲染期间触发客户端上的生命周期方法,例如 componentWillMount()componentDidMount()

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

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

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

ReactDOM.hydrate(元素, 容器[, 回调])

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

【问题讨论】:

    标签: reactjs react-dom react-dom-server


    【解决方案1】:

    我在 TypeScript 系统中读取了ReactDOM.hydrate 的类型:

    (
      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 */
      }
    );
    

    【讨论】:

      【解决方案2】:

      在服务器和客户端之间渲染的元素可能不一样,因为最初这些元素在服务器的内存中被渲染为文本,因此它们没有被挂载。当内容被移动到客户端时,它可以通过hydrate 重新附加以做出反应,这是假的“渲染”,以连接其余的反应功能,例如事件。

      为了判断它什么时候水合,这里有一篇来自互联网的文章,我发现它清楚地说明了上述合理性。 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>
          )
      }
      

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

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

      【讨论】:

        【解决方案3】:
        1. 由于 ReactDOM.hydrate 被(并且应该)在客户端调用,那么 YES 它应该运行 componentDidMountcomponentWillMount 在服务器上渲染时已被调用。 componentDidMount 不在服务器上运行,因此当您调用 hydrate 时,应用程序会运行该事件。

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

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

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

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

        所以你可以看到它做了一个渲染过程。如果没有不匹配,React 会为此进行优化。

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

        【讨论】:

        • 似乎componentWillMount 在调用hydrate 之后在服务器和客户端都被调用。我试图找到一种方法来区分正在安装和水合的元素和有问题的元素。欢迎提出想法!
        • @AndreyFedorov 取决于手头的用例。你想做什么?
        • @Andrey,可能使用useEffect,如果已安装,则应调用effects
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多