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 => Portals
和 Context
解决不同的目的,一个是在任何级别注入 DOM,另一个是在任何级别注入 props。 Context
可以模仿 Portals
但 Portals
目前无法模仿 Context
,至少在没有引入代码异味的情况下是这样。
注意:以下是基于我对这两个概念的理解,如果有人对此有进一步的想法或更正,请随时编辑答案。
据我所知,Portals
顾名思义,是一种用于渲染不需要在组件树层次结构中的组件的途径。这对于Modals
、Popovers
或任何需要在树中特定位置缝合的组件非常有效。
Context
用于与各种兄弟组件和子组件进行通信,而无需从父组件一直向下传递道具到预期组件。当然,这是一个重要的功能,但它仍处于实验阶段,可能是因为这可以通过event-emitters
和Redux
、MobX
实现集中状态管理。
我假设您的 i18n
用例需要跨组件进行大量通信,您可能希望查看这篇精彩的文章
COMPONENT COMMUNICATION
门户和上下文有助于实现这种通信,但存在差异。 Portals 可以在任何级别渲染或注入 DOM,而 Context 可以在子组件树中的任何级别注入 props。
您总是可以使用Context
实现Portals
能够做到的事情,但我不认为Portals
可以模仿Context
的功能。
EG: 可以使用Context
来模仿Portals
所做的事情。在 Portals
AFAIK 中,您只能发送 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-emitters
与Context
可能被弃用的唯一原因。
【讨论】:
嘿,但正如在 react 文档中提到的门户一样,该道具将可用于门户,就好像它是组件的常规子级一样。通过这种方式,道具可以发送到反应层次结构中的任何位置。你不认为这是一些类似于上下文的东西吗?? 但是你怎么能把道具从父母那里寄给第四个孙子呢?除非您在父母的渲染方法中提到第四个孩子<Child4 parentProps=... />
,而第三个孩子也渲染<Child4 props=... />
。我无法想出一个合适的例子来说明为什么使用 Portal 来传达 props 不是一个好主意,但是如果您遇到任何用例,请随时将其添加到答案中。
使用“this.context”。您使用的是新门户还是旧门户?以上是关于React 16 的 Portal API 是否要取代 Context API?的主要内容,如果未能解决你的问题,请参考以下文章
无法将使用 React Portal 和 Tailwind CSS 的 `@headlessui/react` 中的 `Dialog/Modal` 居中?