React 16 的 Portal API 是否要取代 Context API?

Posted

技术标签:

【中文标题】React 16 的 Portal API 是否要取代 Context API?【英文标题】:Is React 16's Portal API meant to replace the Context API?React 16 的 Portal API 是不是要取代 Context API? 【发布时间】:2018-05-24 13:23:12 【问题描述】:

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

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

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

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

【问题讨论】:

【参考方案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”。您使用的是新门户还是旧门户?

以上是关于React 16 的 Portal API 是否要取代 Context API?的主要内容,如果未能解决你的问题,请参考以下文章

[react] 请说说react中Portal是什么?

盘点 React 16.0 ~ 16.5 主要更新及其应用

如何从 React 16 门户获取 ref?

javascript 旧版React Portal

是否可以单独使用react.js创建api?

无法将使用 React Portal 和 Tailwind CSS 的 `@headlessui/react` 中的 `Dialog/Modal` 居中?