React v16.6.0: lazy, memo and contextType
reactjs.org
reactjs.org
Probably I'm just not doing anything very sophisticated. It's just a plain old form driven website - that would account for it.
When I do ReactJS I'm building much more powerful UI features. The Django stuff is just a bunch of forms and that is really easy to drive.
Lately I've been writing little personal projects using Vanilla JS. There's something rather therapeutic about limiting one's self to zero dependencies. I'm wildly surprised every time I come back to Vanilla JS to see just how many core features there are. I can do modules in the browser now! Yippee!
And beyond that, not even using JS and just using Django Templates or Jinja is great too.
But I write a lot of software that monitors and controls mobile robots in warehouses. For that kind of wild state management of 100+ data sources, all with their own incomplete states, controls, unpredictably erroneous behaviours, React + Redux is just a godsend.
I think that part of it is just experience. You'll slowly learn to better predict which projects are likely to grow, especially in a way that needs a more expressive foundation.
I also think that the, "aw crap I have to re-write this from Django Templates to React" isn't exactly a bad thing. You've probably learned a ton about the problem you're solving by focusing on the problem directly in front of you[1] rather than trying to plan for the future problems that you don't quite understand yet. So when you tear it down to build the next iteration, the code you're replacing wasn't the valuable part.
[1] Not all projects are organic. But the ones that are, really benefit from a, "get this out in 2 weeks and learn what we don't yet know about it" rather than spending months trying to perfect some product that we're mostly just guessing at.
- F. Brooks
There were times when javascript === jquery. Nowdays javascript === react.
That's why I built the following project: https://github.com/silviogutierrez/reactivated
It's very early on, but essentially, completely replaces the template rendering with React components. Still regular markup, but whenever you need dynamic behaviors, it's trivial. And it's all server side rendered.
So basically, looking at https://github.com/silviogutierrez/reactivated/blob/master/c...
You can see the traditional Django context becomes "Props" in the top level component. Then it's React all the way down.
Notes:
1. The most complicated part is the initial setup. You do need to run NodeJS, webpack + Django server. Working on improving that.
2. I like TypeScript and use it here. But theoretically it'll be optional. The Django+Python part is also statically typed using MyPy.
3. No instructions whatsoever yet. But you can see a live site using this stack here: https://www.silviogutierrez.com/ . Notice it's server rendered but has dynamic behaviors that are trivial in React but harder with jQuery + Django. Example: https://www.silviogutierrez.com/blog/making-cck-fields-read-... Look at the nested commenting and moving the form around. Very easy in React.
4. Because of the architecture, adding a much-better-turbolinks style Ajax is trivial. Click around the site above (loading indicator not yet added). The page is re-rendered entirely on the client but gets a server AJAX response.
Hope that's interesting info. If you'd like to try it out, definitely let me know. Once you overcome the setup hurdles, it's amazingly productive. As in, if all you wish to do is `{{ form }}` like old school Django, here's the equivalent sample template: https://github.com/silviogutierrez/reactivated/blob/master/c...
Edit: try to make it server agnostic, if open source is your intention ( and not just personal website use case ).
However, would like to compile all the reactjs stuff before including it in flask/django. You could look into the https://github.com/nozzle/react-static project to use their static compiler (which does React -> static html/js) to achieve this exact thing.
Second: React does a DOM diff and only updates the components that changed. So it's super fast.
Third: when you DO need to use the raw JSON, you have access to it.
Fourth: rebinding behaviors (onClick) etc is done by React seamlessly. And again, uses the DOM diff to be efficient.
In the site you linked to, the scroll position gets messed up as you go back and forth between “pages” and click on links — problems that don’t occur when you fully re render a page.
Efficiency in speed: likely very little over just requesting the HTML via AJAX.
As far as scrolling/etc: that behavior is super buggy and I never really tested it. I "turned on" the turbolink-esque behavior as a test but it needs far more work.
In any case, one can just turn it off and revert to regular SSR behavior instead of the AJAX-ey one. I might even do that because, in general, I want my page to show the traditional loading icon in place of the favicon.
--
In your https://github.com/silviogutierrez/reactivated/blob/master/c...
import {Form} from '../components/Form';
I can't find `../components/Form`. Where is the source for that?---
Here are the fields I was able to extract, meaningfully.
https://github.com/pycampers/react-pages/blob/417ec24129b80b...
It still doesn't seem enough for building anything serious though.
Data still comes from an API, so the front end is still decoupled from the back end, and anyone that is not a JS ninja can still contribute to the codebase since the project structure is really simple.
This is an internal project so we can tell our users to use latest Chrome to avoid transpiling and such, but configuring webpack would still be possible.
I really recommend the approach.
A lot of people think getting the data from an API automatically means building a single-page-application while in fact you could use this approach with Jekyll to create a static site, or even use server side code to generate dynamic markup and still consume an API.
I seem to remember reading that adding something like `PureComponent` or implementing `shouldComponentUpdate()` can actually slow things down due to the cost of props/state comparison?
Either way thanks for another great release team! Suspense has me super excited!
Brian recently wrote a profiler to help you find where plugging memo is useful:
https://reactjs.org/blog/2018/09/10/introducing-the-react-pr...
I haven't seen anything yet about the Suspense component supporting this. I imagine you could wrap the suspense component with your own to achieve this behavior, but it's nice not to have to reimplement.
There is more nuance to it — essentially, React Loadable renders a _hole_ instead of the spinner in this case. Which isn't much better than a spinner because you still see the intermediate state.
With the current release of Suspense, you can do it if your fallback component renders spinner after a timer. So that's not difficult. But we also don't think it's good either.
Instead, when we release Concurrent Mode, you can _avoid showing the change altogether_ until a certain threshold passes. That's the `maxDuration` prop (which doesn't do anything outside of Concurrent Mode).
So you don't even show a hole. Instead, the whole UI is "suspended". And then the fallback kicks in if takes too long.
This might be a bit hard to imagine since no mainstream UI library can do this yet. So you might want to check the second half of my talk (on Suspense) to get a sense for what it's like: https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-...
That's our end game.
1. We support using mutable objects in props. Even if a prop is reference identical to the last render, the component might be reading some property of it that has changed.
2. Checking equality of props takes time. In the (common) case where a parent rerenders and it’s children need to change in response, any time we spend comparing will be extra overhead on top of the actual render cost. Often rerendering is fast anyway and adding more comparisons only makes it slower.
Because of these, we don’t do these checks by default. Instead, we recommend adding memo/PureComponent/shouldComponentUpdate in places where you know it will make a difference.
Unfortunately there is a long backlog of PRs to the React docs waiting for review so I don't know if/when this info might be incorporated into the docs. Also React is evolving so fast that it would need to be updated, e.g. to mention memo, and given that fast evolution I can understand why there's a backlog. But I do hope that someone on the React team eventually has time to look at adding more explanation to the "Optimizing Performance" section.
I still need to go find my "aha!" moment for contexts. I get them but I haven't developed that intimacy where I know when I should use them.
Also I'm finding it trickier to know which method for component definition to reach for. I love that we have freedom of choice. But I struggle to pick between classes (pure and not), class methods (perhaps to clean up big render() methods or define class-relevant subcomponents), and functional components (memoized or not). I had someone getting into React asking me about it and I didn't have a really solid answer. I think I just confused them. This is probably just a tutorial/documentation/examples kind of problem.
Love that React is always improving!
I suppose context is a way of doing that. But I'm just don't grok it yet. I should experiment a lot more.
See my post "Practical Redux, Part 6: Connected Lists and Performance" [0] and the Redux FAQ entry on using React-Redux [1] for more details.
Also, we're completely rewriting the React-Redux docs from scratch, and they now have their own site [2] . We've got some new tutorial material available, and a guide section on writing `mapState` functions. The new section on using `mapDispatch` should be up soon, and we've got a lot more planned, including sections on writing selectors, performance optimizations, and how React-Redux works internally.
[0] https://blog.isquaredsoftware.com/2017/01/practical-redux-pa...
Other examples are react-redux itself (which uses the legacy context API) or react-intl (which uses the legacy context API), or a themeable widget set. You put a wrapping context at the top of your tree like <Provider>, <IntlProvider messages={someMessages} locale={this.state.locale}> or <ThemeProvider theme={myEmployersColours}>, and then nested deeply in the application you use a <Message> that will look at the context provided by the IntlProvider, or the context provided by the theme, to pull out the actual message/colors it should show.
Basically, context is useful for encapsulating cross-cutting concerns :).
Say, 100 robots driving around, displayed by a map component. I want to handle the addition of removal of a robot as an action but the actual 10hz pose updates can just be handled by the canvas and ignored by react entirely.
Maybe even context for camera streams too.
Previously I would just handle a websocket stream as a global. Yuck.
We're actually working on converting React-Redux to use `createContext` in version 6. I had hoped that it would be a big performance improvement, but unfortunately our (admittedly limited) perf benchmarks indicate that the experimental v6 branches are slower than our current v5 release build. In v5, the individual connected components subscribe to the Redux store, and can bail out of calling `setState()` if no update is necessary. In v6, we've only got one subscription (in `<Provider>`), but any Redux store update requires that React walk the tree and update the context consumers so they can run `mapState`. So, React _always_ gets involved, whereas before we might skip React if nothing had changed.
Per that issue, I'm hopeful that the React team can optimize deep context updates in the near future.
static contextType = SomeContext
they did something like: static contextMap = {
form: FormContext,
app: AppContext,
}
as it seems limiting to only allow one context.In the example above, the context values would be available in this.form and this.app
We intentionally didn't do it for several reasons:
* It adds extra object allocations on every render which adds up when your project grows
* It's harder to express in a type system (e.g. Flow or TypeScript)
You can use the low-level Consumer API to read multiple contexts but in this particular shortcut we're not going to support it.
I don't know about flow, but TypeScript is pretty flexible there. With mapped types you should be express anything you need.
We usually recommend avoiding deep checks because
(a) the concept of deep equality is pretty nebulous and hard to design in a predictable, precise way, and
(b) deep equality checking can be slow, often just as slow (or slower) than the actual rerender – in which case the memoization is only hurting you.
(If you want to do deep equality anyway, you can pass a second argument to React.memo to specify a custom comparator.)
Seems like it’s more of a monkey patch for people who liked “the old way”.
https://github.com/reactjs/rfcs/blob/master/text/0065-contex...
The contextType API serves as a convenience for the most common case of accessing context today. While the existing render prop API is more versatile, the fact is it's awkward in some cases with classes (e.g. when you need to access it in lifecycle).
And unfortunately that means that people are stuck using the legacy context API which is even worse (it makes React bigger and slower). So we're adding a convenience to help people migrate to the new implementation with a slightly more familiar syntax.
I guess in a way it _is_ a compromise, but in our view it's better than if people just kept using the legacy context API.
Hope that makes sense.
All our releases support SSR. But some specific features need to wait for a new async server renderer. I can't tell you when that's going to happen although it's most likely within 2019.
Is there an RFC somewhere about that new async server renderer?