Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new Context API in React 16.3 #5901

Closed
timdorr opened this issue Jan 26, 2018 · 27 comments
Closed

Use new Context API in React 16.3 #5901

timdorr opened this issue Jan 26, 2018 · 27 comments

Comments

@timdorr
Copy link
Member

timdorr commented Jan 26, 2018

Re: facebook/react#11818 and reactjs/rfcs#2 (<- Warning: super long PR)

There's a new render prop/children-as-function API for context coming in the next React minor release. The big thing that's relevant to us: It works across shouldComponentUpdate boundaries without the need for subscriptions. So, no more need for the blocked updates guide. Huzzah!

It will require some refactoring. And backwards compat is going to be...interesting. We may have to bump to 5.0.0 to make it clean. FWIW, React Redux is considering this too, so we're not alone. (The whole major version/breaking changes debate is probably going to fire up again 🙄 )

I'm going to start tooling around with it over the weekend. The fun bit: turning on this and async rendering at the same time 😲

@brianespinosa
Copy link

This is the best news I've heard all week.

@pshrmn
Copy link
Contributor

pshrmn commented Jan 26, 2018

Handling backwards compatibility is the big issue for me. I half feel like there will need to be two versions of components (<Link> & <LegacyLink>?) until the old context can safely be removed, but I haven't wrapped my head around what will be required yet.

@timdorr
Copy link
Member Author

timdorr commented Jan 26, 2018

It's pretty easy to do feature detection:

if (React.createContext) {
  // new hotness
} else {
  // old and busted
}

It's just a matter of how different the refactor would be and how much that would bloat the bundle size.

@odiseo42
Copy link

My prayers have been answered! \o/

@Inucoder
Copy link

I'm very happy about the update blocking issue getting finally fixed! It's really a pain to deal with when working with libraries like react-redux or your own shouldComponentUpdate implementations on large projects. I have spent several hours working around the problem and my guess was you guys were going to solve it for the next major release!

@pshrmn
Copy link
Contributor

pshrmn commented Jan 27, 2018

Edit no. 2: I think I just misunderstood this before. I'm reading the tests now and nesting is supported. 😅

@Inucoder
Copy link

@timdorr, do you have an ETA for when this update might make it to a release? That would help our team plan ahead because we have a few React Router related tasks in schedule that would not make sense to execute if this nice fix gets released. Regards, keep the great work.

@pshrmn
Copy link
Contributor

pshrmn commented Jan 29, 2018

@Inucoder You can watch #5908 but there isn't really a schedule and it is more dependent on React releases. React 16.3 should be released in a few weeks, so that is the first time anyone can easily test the new context API out, and even then it will be "unstable". React 17 should be when the stable context API is released, which is on the order of months.

@hilkeheremans
Copy link

A potential, but probably not ideal alternative for backwards compatibility is to polyfill when needed:
https://github.com/thejameskyle/create-react-context

Not actively suggested this as I haven't tested this, just throwing it out there as an option.

@timdorr
Copy link
Member Author

timdorr commented Feb 8, 2018

@hilkeheremans Yes, I'm doing that in #5908

@corysimmons
Copy link

@hilkeheremans Seems to work fairly seamlessly https://codesandbox.io/s/1vnnrmnv4

@sshmyg
Copy link

sshmyg commented Mar 30, 2018

What about new context API for react-router 3?

@timdorr
Copy link
Member Author

timdorr commented Mar 30, 2018

@sshmyg We're only supporting 3.x with bug fixes indefinitely. A refactor to use the new context API would be too substantial.

@dantman
Copy link

dantman commented Apr 10, 2018

This would fix #6072

@timdorr
Copy link
Member Author

timdorr commented Apr 10, 2018

@dantman No, that's caused by an upstream React issue.

@dantman
Copy link

dantman commented Apr 10, 2018

@timdorr What React issue? The only issue I see is one complaining that the new context system's Provider acts like a component with a "pure" shouldComponentUpdate. Which if that is the problem then that is react-router's fault for not working, the PureComponent behaviour has been known about forever. The old context API is not guaranteed to ever update context, everyone using the old context API for dynamic context must use a subscriber pattern. If react-router is not working right because it is expecting the old context API to handle updates itself, that is a bug in react-router. I've been using react-redux fine before 16.3 was released and it's still working fine now that my app is using the new context API and just about every one of my components uses PureComponent, because react-redux correctly passes a subscriber down instead of dynamic data.

If that is the problem, then that will be fixed by switching to the new context API. Because the new context API does update dynamic data.

@timdorr
Copy link
Member Author

timdorr commented Apr 10, 2018

@johannessteu
Copy link

Any updates on this?

@remix-run remix-run deleted a comment from dantman Apr 16, 2018
@pothos-dev
Copy link

pothos-dev commented Apr 22, 2018

Just a heads up, here is my version of using the new context API to provide RouteComponentProps without relying on withRouter at call side, and also a workaround to use the context consumer even though it is bugged right now. I hope this will help some readers of this ticket.

import * as React from 'react';
import {RouteComponentProps, withRouter} from 'react-router';
import {BrowserRouter} from 'react-router-dom';

// Creates a Provider/Consumer pair for the new React Context API (we skip providing default values)
export const RouterContext = React.createContext<RouterContextData>({} as RouterContextData);

// The values available to a RouterContext.Consumer - currently just everything react-router gives us
export interface RouterContextData extends RouteComponentProps<any> {}

// HOC that sets up the RouterContext for the given render tree
export function RouterContextProvider(props: { children: React.ReactNode }) {
  // Use withRouter here to get the RouterComponentProps out of the outdated react-router context api
  const ConnectedContextProvider = withRouter(ContextProvider);

  // Pass it into the shiny new context api
  function ContextProvider(props: RouteComponentProps<any> & { children: React.ReactNode }) {
    return (
      <RouterContext.Provider value={props}>
        {props.children}
      </RouterContext.Provider>
    );
  }

  // set up BrowserRouting and the new context
  return (
    <BrowserRouter>
      <ConnectedContextProvider>
        {props.children}
      </ConnectedContextProvider>
    </BrowserRouter>
  );
}

// Workaround for https://github.com/ReactTraining/react-router/issues/5901
// Using the RouterContext.Consumer will not provide the correct match params.
// Instead, use RouterContextConsumer, which still relies on the old context api.
// As soon as this is fixed, we can just replace all RouterContextConsumer by RouterContext.Consumer.
export const RouterContextConsumer = withRouter(function (props: RouterContextConsumerProps) {
  return props.children(props);
});

interface RouterContextConsumerProps extends RouteComponentProps<any> {
  children: (ctx: RouterContextData) => React.ReactElement<any> | null;
}

@vladp
Copy link

vladp commented May 27, 2018

@bearbytes thx for posting your solution. I am running into an issue and wanted to ask if you had seen this..

Using RR 4.3-rc2, React 16.3.2 (which I now essentially pulling 16.4) I created an application-wide context with a 'store-like' data structure.
I can pass and see the store everywhere I need to. However, when I make an update to the store, my components (that are all sitting within react router) -- do not get re-rendered at all. shouldComponentRender is not getting called either.

I am not changing any routes/paths when I am performing my context update, none of my components are pure.

@MikeMuxika
Copy link

@vladp Not sure if this will help or not but if you look at the documentation withRouter section on the react training site, they include the following important note.

withRouter does not subscribe to location changes like React Redux’s connect does for state changes. Instead, re-renders after location changes propagate out from the component. This means that withRouter does not re-render on route transitions unless its parent component re-renders. If you are using withRouter to prevent updates from being blocked by shouldComponentUpdate, it is important that withRouter wraps the component that implements shouldComponentUpdate.

If you try this, it may solve your issues.

@vladp
Copy link

vladp commented May 31, 2018

@muxica thank you. I do have withRoute on some components. WIll troubleshoot with that in mind. Thx again.

@itsdouges
Copy link

@timdorr do you need any help getting this across the line? the update blocking behaviour isn't fantastic, I'm surprised it hasn't been a priority to resolve it. surely its one of the biggest pain points of using react router today.

@crobinson42
Copy link

Woohoo! This is yuuuuge for react-router!!! Thx guys!

@Strate
Copy link

Strate commented Sep 26, 2018

Am I right, that this fixes blocked updates completely?

@timdorr
Copy link
Member Author

timdorr commented Sep 26, 2018

Yes, it will fix them.

@ryaninvents
Copy link

Great work, thank you for solving this!

I've read the thread and it looks like the release of this change is waiting for the new Context API to be considered stable. Is the next release still holding off for React 17, or sooner since it looks like that API is now stable?

@lock lock bot locked as resolved and limited conversation to collaborators Nov 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests