让消费者提供提供者的目的是什么?

时间:2019-12-12 12:21:47

标签: reactjs react-context

当我在其主要提供程序中遇到以下代码时,我正在看react-jss的源代码,这些代码称为JssProvider

  renderProvider = (parentContext: Context) => {
    const {children} = this.props
    const context: Context = this.createContext(parentContext, this.prevContext)
    this.prevContext = context
    return <JssContext.Provider value={context}>{children}</JssContext.Provider>
  }

  render() {
    return <JssContext.Consumer>{this.renderProvider}</JssContext.Consumer>
  }
}

Source


这让我很困惑,起初我认为这是一种无需过多努力即可访问先前上下文的递归方法。但是我试图在这样的沙盒中重现它

const context = React.createContext();
const { Provider, Consumer } = context;

const FooProvider = ({ children }) => {
  const [state, setState] = React.useState({
    value: "foo",
    setValue: value => setState(p => ({ ...p, value }))
  });

  const renderProvider = context => {
    console.log(context);
    return <Provider value={state}>{children}</Provider>;
  };

  return <Consumer>{renderProvider}</Consumer>;
};

function App() {
  const onClick = setter => {
    setter("bar");
  };
  return (
    <FooProvider>
      <Consumer>
        {context => (
          <div>
            {context.value}
            <button onClick={() => onClick(context.setValue)}>Change</button>
          </div>
        )}
      </Consumer>
    </FooProvider>
  );
}

Edit restless-waterfall-0veto

问题是提供给context的{​​{1}}始终是renderProvider

此特定模式的目的是什么?我在这里想念什么?

1 个答案:

答案 0 :(得分:3)

当组件树中有多个相同的提供程序时,它们将彼此“阴影化”,其方式类似于具有相同名称shadow的变量彼此之间的方式。每次渲染消费者时,它只会从树上最近的提供者那里看到值。

因此,他们在这里所做的就是利用这一点。提供程序存在于树的顶部附近,并为其后代提供值。这些后代之一侦听该值,然后立即制作该值的修改版本并提供它。因此,低于此第二个提供程序的任何内容都将只能看到修改后的值,而看不到原始值。

我不确定他们在代码中使用了什么,但是我以前在一些方面使用了它:

1)用于仅覆盖特定部分的页面主题。

我们的应用程序顶部将有一个主题提供程序,用于指定用于样式的常量。但是,在树中间的某个地方是一个组件,它将读取该全局主题,覆盖一些值,然后向其后代提供经过修改的主题。这些后代只能访问修改后的主题。

在我们的案例中,这使我们可以预览主题在全局应用时的外观。

2)用于汇总有关组件树的元数据。

我们有一个用例,其中的组件需要知道它们在其中使用的应用程序的区域,因此我们在树的顶部附近的位置设置了一个提供程序,提供了一个基本为{page: 'Login'}的值。 (管他呢)。在其下方的是一对消费者/提供者,它将接受并添加到其中,提供{page: 'Login', section: 'Credentials'}。然后是将其再次增加到{page: 'login', section: 'Credentials', subsection: 'email'}的那个。

最后,任何只消耗上下文(不提供其自身值)的组件都可以知道它在应用程序中的位置。它只会从最接近的祖先那里获得价值,因此它只具有正确的信息量。

  

问题在于提供给renderProvider的上下文始终未定义。

您看到未定义的原因是这是您创建的上下文的默认值(因为您没有向React.CreateContext()传递任何内容),并且您只有一层嵌套。如果您有多个这样的消费者/提供者对彼此嵌套,则每个都会从最近的祖先注销,而最上面的则注销未定义。您只有最顶层的那个。