7

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

我还注意到他们正在引入React 16 的 Portal API,但不确定这是否是为了取代 Context API。

那么,如上所述,React 16 的 Portal API 是否意味着要替换 Context API?

编辑:为了搭载这个主题,conext 是管理 i18n 本地化的最佳方法吗?

4

2 回答 2

5

TL;DR =>PortalsContext解决不同的目的,一个是在任何级别注入 DOM,另一个是在任何级别注入 props。Context可以模仿Portals,但至少在不引入代码异味的情况下Portals不能模仿。Context

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

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

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

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

组件通信

在此处输入图像描述

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

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

EG:可以做这样的事情来模仿Portals使用Context. 在PortalsAFAIK 中,您只能发送 DOM Nodes 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

于 2017-12-11T04:18:42.733 回答
1

Portal API 与 Context API 不同,

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

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

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

ReactDOM.createPortal(child, container)

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

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

Context 旨在共享可被视为 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 本地化的最佳方法吗?

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

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

于 2018-06-25T08:52:56.057 回答