【问题标题】:Is React 16's Portal API meant to replace the Context API?React 16 的 Portal API 是不是要取代 Context API?
【发布时间】:2023-09-29 07:50:01
【问题描述】:

我注意到新功能 portals 做同样的事情但更好?我对门户不太了解,但它似乎是管理嵌套组件更新的新方法? 我知道 Reacts Context API 是实验性的,并且注意到 componentDidUpdate 不再接收 prevContext 并且他们放弃了 contextTypes

我还注意到他们正在引入React 16's Portal API,但不确定这是否旨在替换 Context API。

那么,如上所述,React 16 的 Portal API 是否旨在取代 Context API?

编辑:要捎带这个话题,conext 是在 react 中管理 i18n 本地化的最佳方法吗?

【问题讨论】:

    标签: javascript reactjs portal react-fiber


    【解决方案1】:

    Portal API 与 Context API 不同,

    Portals 提供了一种将子节点渲染到 DOM 节点的一流方法 存在于父组件的 DOM 层次结构之外。

    当您可能想要渲染 Modals 或 Popovers 时,门户很有用,它们需要位于当前 DOM 层次结构之外才能拥有正确的 z-index。大多数情况下,您会直接在顶层渲染它们。但是,使用 Portal,您可以在任何层次结构级别呈现 DOM 元素。

    React 16 中,可以像这样创建门户

    ReactDOM.createPortal(child, container)
    

    另一方面,Context 用于将数据传递到不同的组件,而无需在每个级别向下传递。您可能有不同级别的组件,其中一些可能非常嵌套,并且在每个级别一直向下传递道具可能不是一个很好的解决方案,并且它会带来显着的性能障碍,因为很多更高的级别实际上可能不是使用这些道具,但仍会重新渲染此类道具更改。

    从 v16.3.0 开始,React 引入了一个新的context API,并且上下文不再是实验性的。

    上下文旨在共享可被视为“全局”的数据 React 组件树,例如当前经过身份验证的用户, 主题或首选语言。使用上下文,我们可以避免传递 道具通过中间元素。但它不应该被用来 将道具向下传递几级

    通常你会使用类似的上下文

    export const MyContext = React.createContext();
    
    class Provider extends React.Component {
       state = {
           theme: 'dark'
       }
       handleChange=() => {}
    
       render() {
            return <MyContext.Provider 
               value={{state: this.state, handleChange: this.handleChange}}
               >
                   {this.props.children}
               </MyContext.Provider?>
       }
    }
    

    对于你想使用上下文值的组件,你会写

    import {MyContext} from 'path/to/context'
    ...
    render() {
        return <MyContext.Consumer>
             {(theme) => <div>{theme}</div>}
         </MyContext.Consumer>
    }
    

    要捎带这个话题,上下文是管理 i18n 的最佳方式 React 中的本地化?

    是的,i18n 本地化是使用上下文的一个很好的用例,因为您需要在整个应用程序中传递语言/参数化选择。如果您需要更多地与 API 集成来进行本地化,您可以考虑使用 Redux。

    有关更多详细信息,请查看whether to use Context or Redux上的此答案

    【讨论】:

      【解决方案2】:

      TL;DR => PortalsContext 解决不同的目的,一个是在任何级别注入 DOM,另一个是在任何级别注入 props。 Context 可以模仿 PortalsPortals 目前无法模仿 Context,至少在没有引入代码异味的情况下是这样。

      注意:以下是基于我对这两个概念的理解,如果有人对此有进一步的想法或更正,请随时编辑答案。

      据我所知,Portals 顾名思义,是一种用于渲染不需要在组件树层次结构中的组件的途径。这对于ModalsPopovers 或任何需要在树中特定位置缝合的组件非常有效。

      Context 用于与各种兄弟组件和子组件进行通信,而无需从父组件一直向下传递道具到预期组件。当然,这是一个重要的功能,但它仍处于实验阶段,可能是因为这可以通过event-emittersReduxMobX 实现集中状态管理。

      我假设您的 i18n 用例需要跨组件进行大量通信,您可能希望查看这篇精彩的文章

      COMPONENT COMMUNICATION

      门户和上下文有助于实现这种通信,但存在差异。 Portals 可以在任何级别渲染或注入 DOM,而 Context 可以在子组件树中的任何级别注入 props。

      您总是可以使用Context 实现Portals 能够做到的事情,但我不认为Portals 可以模仿Context 的功能。

      EG: 可以使用Context 来模仿Portals 所做的事情。在 PortalsAFAIK 中,您只能发送 DOM 节点 ReactDOM.createPortal(child, container)。可能有办法实现该功能,但这肯定会导致代码异味。

      class Parent extends React.Component {
      
          getChildContext() {
              return {
                  renderModal: this.renderModal
              }
          }
      
          renderModal = (children) => {
              this.setState({
                  open: !this.state.open,
                  injectableChildren: children
              })
          }
      
          render() {
              this.state.open
                  ?
                  <div>
                      {this.state.injectableChildren}
                  </div>
                  : 
                  null
              // JSX
          }
      }
      
      
      class SomeSibling extends React.Component {
          static contextTypes = {
             renderModal: React.PropTypes.func
          }
      
          handleOnClick = (event) => {
              this.context.renderModal(renderableChildJSX);
          }
      
          renderableChildJSX = () => (
              <div>
                  YAY I AM GETTING RENDERED AT THE ROOT
              </div>
          )
      
          render() {
              return(
                  <div onClick={this.handleOnClick}>
                  </div>
              )
          }
      }
      

      就我而言,我害怕使用Context,尽管它很灵活,因为React 文档总是提到它是一个实验性功能,并反复警告不要全面使用此功能。我的猜测是,React 正在考虑稳定此功能或将其完全从 React 代码库中删除,这可能是双向的风险。

      结论: IMO,Portals 处于当前状态,它试图解决的问题与 Context 的用途完全不同,最好将 event-emittersContext 可能被弃用的唯一原因。

      【讨论】:

      • 嘿,但正如在 react 文档中提到的门户一样,该道具将可用于门户,就好像它是组件的常规子级一样。通过这种方式,道具可以发送到反应层次结构中的任何位置。你不认为这是一些类似于上下文的东西吗??
      • 但是你怎么能把道具从父母那里寄给第四个孙子呢?除非您在父母的渲染方法中提到第四个孩子&lt;Child4 parentProps={...} /&gt;,而第三个孩子也渲染&lt;Child4 props={...} /&gt;。我无法想出一个合适的例子来说明为什么使用 Portal 来传达 props 不是一个好主意,但是如果您遇到任何用例,请随时将其添加到答案中。
      • 使用“this.context”。您使用的是新门户还是旧门户?