上下文API随处使用

时间:2018-09-03 16:27:37

标签: reactjs

我正在尝试使用React上下文api在我的应用程序中实现共享状态。

我正在树的根部创建一个errorContext状态。错误上下文如下所示:

// ErrorContext.js
import React from 'react';
const ErrorContext = React.createContext({
    isError: false,
    setError:   (error) => {}
});

export default ErrorContext;

所需结果

  • 我想从应用程序中的任何位置(特别是在Promise中)更新(使用)此上下文。
  • 理想情况下,将消耗步骤提取到导出的辅助函数中

辅助功能的用法示例

http.get('/blah')
    .catch((error) => {
        HelperLibrary.setError(true);
    })

跟随react上下文文档:

我可以像这样创建提供者:

class ProviderClass {
    state = {
        isError: false,
        setError: (error) => {
            this.state.isError = error;
        }
    }

    render() {
        return (
            <ErrorContext.Provider value={this.state}>
                {this.props.children}
            </ErrorContext.Provider>
        )
    }
}

然后我可以通过在render调用中使用Consumer包装器来使用此提供程序:

<ErrorContext.Consumer>
    {(context) => {
        context.setError(true); 
    }}
</ErrorContext.Consumer>

这种方法的问题

这种方法要求我们团队中的每个开发人员每次希望处理Web服务错误时都要编写许多样板代码。

例如他们必须将ErrorContext.Consumer放置在组件render()方法内,并根据Web服务响应有条件地进行渲染。

我尝试过的

在帮助器函数中使用ReactDOM.render。

const setError = (error) =>{
       ReactDOM.render(
           <ErrorContext.Consumer>
               // boilerplate that i mentioned above
           </ErrorContext.Consumer>,

           document.getElementById('contextNodeInDOM')
       )    }
       export default setError;

为什么这行不通?

由于某种原因,ReactDOM.render()始终将此代码放置在React组件树之外。

<App>
    ...
        <ProviderClass>
            ...
            <div id="contextNodeInDOM'></div> <-- even though my node is here
            ...
        </ProviderClass>
</App>
<ErrorContext.Consumer></ErrorContext.Consumer> <-- ReactDOM.render puts the content here

因此,没有为使用者找到上下文父级,因此它默认为默认上下文(无状态)

docs

  

如果上面没有此上下文的提供者,则使用value参数   将等于传递给createContext()的defaultValue。

如果有人可以帮助我进行下一步,那么我会从Angular来,如果我的术语不正确或者我做的非常愚蠢,我深表歉意。

2 个答案:

答案 0 :(得分:3)

您可以导出HOC以在导出之前包装错误组件,从而消除样板并确保仅在需要的地方提供上下文,而不会与DOM混淆:

// error_context.js(x)
export const withErrorContext = (Component) => {
  return (props) => (
    <ErrorContext.Consumer>
      {context => <Component {...props} errorContext={context} />}
    </ErrorContext.Consumer>
  )
};

// some_component.js(x)
const SomeComponent = ({ errorContext, ...props }) => {
  http.get('/blah')
      .catch((error) => {
        errorContext.setError(true);
      })

  return(
    <div></div>
  )
};

export default withErrorContext(SomeComponent);

现在,React 16.8降落了,您还可以使用钩子更干净地执行此操作:

const SomeComponent = props => {
  const { setError } = useContext(ErrorContext)

  http.get("/blah").catch(() => setError(true))

  return <div />
}

答案 1 :(得分:0)

  

跟随react上下文文档:

     

我可以像这样创建提供者:

     

class ProviderClass { state = { isError: false, setError: (error) => { this.state.isError = error; } }

我不这么认为-应该使用setState反应中有一个通用规则“ 不要改变状态-使用setState()”-滥用会引起很大的反应问题。

我觉得您不了解上下文角色/用法。这更像是通向全球商店的捷径,无需通过深层组件结构将道具显式地传递给孩子(有时更多)。超过10个级别。

  

App> CtxProvider >路由器>其他> ..> CtxConsumer> ComponentConsumingCtxStorePropsNMethods

在某些特殊情况下使用访问具有ID的渲染DOM节点,通常应避免,因为后续渲染会破坏外部所做的任何更改。

如果您需要在主要React应用html节点之外的某个地方渲染某物,请使用portals