Skip to content

Imperative wrappers can't access current context value in commit phase #13336

@gaearon

Description

@gaearon

Sometimes we have an imperative wrapper like this:

componentDidMount() {
  renderSomethingImperatively(this.props)
}

componentDidUpdate() {
  renderSomethingImperatively(this.props)
}

render() {
  return null
}

Portals eliminated the need for this for regular DOM jumps. But we still need this for embedding renderers (e.g. react-art does this) and use cases like "Vue inside React".

For cross-renderer embedding, maybe we could extend portals to do that (#13332). There are still imperative use cases for cross-library rendering though.

One thing that becomes annoying is that new context won't propagate down through this imperative boundary. This is because we don't maintain a stack in the commit phase. We're traversing a flat linked list of effects. So we don't actually know what context value is current by the time componentDidMount or componentDidUpdate fires.

For react-art and friends, this means context from a host app is not accessible. This is quite annoying. You could hack around it with something like

<MyConsumer>
  {value =>
    <ReactART.Surface>
      <MyContext.Provider value={value}>
        <Stuff />
      </MyContext.Provider>
    </ReactART.Surface>
  }
</MyConsumer>

But this is neither obvious nor convenient. You have to anticipate all contexts that can get used below.

This seems even less convenient for imperative cases like "Vue inside React".

componentDidMount() {
  renderSomethingImperatively(this.props) // ???
}

componentDidUpdate() {
  renderSomethingImperatively(this.props) // ???
}

render() {
  // <MyConsumer>{value => ???}</MyConsumer>
  return <div />
}

Seems like you could use unstable_read() in getDerivedStateFromProps and that would put it into state so you can use it in lifecycles. So maybe that's sufficient. It still means you need to be explicit about which contexts you want to remember though.

I wonder if we can find a better solution to these use cases.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions