13 ms·
React v16.6.0: lazy, memo and contextType
- mbrowne 8y agoI am wondering how to avoid unnecessary re-renders using `contextType`. With the render props pattern, you could write a component e.g. <Subscribe> that subscribes to a store and accepts a prop to indicate the specific data dependencies of your component (similar to mapStateToProps() in redux -- here it could be called mapContextToProps()). It's nice to be able to use `static contextType` but it would re-render anytime any property of your context object changes (just as would be the case when using a Consumer directly). That might be fine for something like a theme but wouldn't scale to a more general state management solution.
- mbrowne 8y agoThinking about it some more, for function components I suppose this might be a good use case for a hook...
- breeny592 8y agoGreat work from the React team on this release - it's exciting to see some big enabling features like suspense and lazy being baked into the library (rather than falling back on solutions like react-loadable).
- platz 8y agois it just me or does contextType/context abandon the FP parts of React?
- sorahn 8y agoI felt that way too. Seems like it’s more of a monkey patch for people who liked “the old way”.
- danabramov 8y agoNot quite sure what you mean. Maybe the RFC might explain the motivation a bit more? https://github.com/reactjs/rfcs/blob/master/text/0065-contexttype.md 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.
- nicoburns 8y agocontextType API looks great. I thought when I saw the new context API that it looked neat from a code cleanliness point of view, but a bit of a pain to use. This looks much easier :)
- frio 8y agoIt's just another input. Previously, React derived a rendered set of virtual-dom nodes from `props` and `state`. Now, it' derives that set of nodes from `props`, `state` and `context`. It's useful syntactical sugar.
- dustingetz 8y agoClojureScript dev here, we use the context pattern a lot in http://www.hyperfiddle.net/ http://www.hyperfiddle.net/ and we feel it does not harm our ability to reason about referential transparency
- jliptoo 8y agoDoes anyone know if the next version will be 17.0 or can we expect more 16.x version even by mid 2019? Need this info for work.
- danabramov 8y agoWe expect to release more minor version(s) prior to 17.
- jliptoo 8y agoThanks. Do you know if react 17 will be out by mid-2019? Need this info for work. Specially support for SSR. Thanks.
- danabramov 8y agoWhat do you mean by "support for SSR"? Can you elaborate? 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.
- jliptoo 8y agoI'm talking about react Suspense for SSR. The blog post says "Note: This feature is not yet available for server-side rendering. Suspense support will be added in a later release.". Is there an RFC somewhere about that new async server renderer?
- danabramov 8y agoNot yet. I expect that it will be done in 2019 but can't give you anything more specific at the moment.
- thesunny 8y agocontextType is a much needed shortcut but I wish instead of this: 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
- danabramov 8y agoThis has been suggested in the RFC discussion (https://github.com/reactjs/rfcs/pull/65 https://github.com/reactjs/rfcs/pull/65). 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.
- pcmaffey 8y agoThe other angle to solving this problem would be adding lifecycle methods to React.Context (instead of using render props), which could eliminate the need for multiple contexts. Making Consumer contexts more efficient & composable.
- danabramov 8y agoWe've thought about a spectrum of solutions and plan to present more proposals soon.
- wereHamster 8y ago> It's harder to express in a type system (e.g. Flow or TypeScript) I don't know about flow, but TypeScript is pretty flexible there. With mapped types you should be express anything you need.
- ianschmitz 8y agoWith the addition of `React.memo`, is it still the recommendation from the React team that we only use `React.PureComponent` and `React.memo` in places where we profile and identify performance bottlenecks? 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!
- danabramov 8y agoYeah, nothing changed there. If you run checks that are always false then it's wasted time on checking. Brian recently wrote a profiler to help you find where plugging memo is useful: https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html https://reactjs.org/blog/2018/09/10/introducing-the-react-pr...
- dbbk 8y agoEvery time I see stuff like this it just makes me think, why does the developer have to care about this? For example take Glimmer, you never have to do `shouldComponentUpdate` or anything like that, it's just maximally performant out of the box.
- deleted 8y ago[deleted]
- throwaway3265 8y agoIs React.memo comparing deeply/recursive or at least deterministic JSON.stringify comparison? Or still going for shallow comparison?
- sophiebits 8y agoStill shallow. 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.)
- throwaway3265 8y agoI agree about those statements, just curious since that was probably the most important concept I had to learn about "advanced" React.
- deleted 8y ago[deleted]
- andrewstuart 8y agoI'm a huge ReactJS fan, but right now I'm doing some development with Django and plain old HTML/JavaScript template forms and I'm finding it incredibly easy and my general pain level seems to be lower. I haven't figured out why exactly. Probably I'm just not doing anything very sophisticated. It's just a plain old form driven website - that would account for it.
- danabramov 8y agoMaybe you were using React for something that isn't highly interactive and thus React was adding more friction than utility?
- andrewstuart 8y agoI think you are exactly correct, now I give it some thought. 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.
- Waterluvian 8y agoWhen to use the more powerful tools is an important (and tricky) lesson to master. Not every project needs React. 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.
- andrewstuart 8y agoOne of the things that makes it hard to choose which technology you begin with is that small projects don't stay small, even if you thing they will. So the risk is I think "hey it's s small project, I'll whip it up in Django", and then of course in six months I'm cursing myself for not starting in React.
- Waterluvian 8y agoPretty excited by these features. Great work! 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.
- cstrat 8y agoI've got apps where I am passing props down a few levels (perhaps three components deep). What I don't completely understand if Context is a _better_ solution for what I am doing or if it is just another way to accomplish the same thing. Love that React is always improving!
- Waterluvian 8y agoI hear you. I usually use Redux and I find myself `connect`ing a lot more things than I used to. So far I haven't found any seriously painful reasons to do so. Like each tab of my phone app is connected. Each major "concept" in my app is connected. Generally everything above connected components are purely layout/app navigation and it seems to work. I'm betting Dan would suggest it's not necessarily a bad idea and might be fine. I suppose context is a way of doing that. But I'm just don't grok it yet. I should experiment a lot more.
- acemarke 8y agoGenerally, connecting more components to Redux is better for performance. The cost of more `mapState` calls is less than the cost of more "wasted" renders, and when a component needs smaller pieces of the Redux state, other state changing means it's not affected. 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-part-6-connected-lists-forms-and-performance/ https://blog.isquaredsoftware.com/2017/01/practical-redux-pa... [1] https://redux.js.org/faq/reactredux https://redux.js.org/faq/reactredux [2] https://react-redux.js.org https://react-redux.js.org
- hoppelhase 8y agoDo lazy + Suspense replace the react-loadable [1] package? [1]: https://github.com/jamiebuilds/react-loadable https://github.com/jamiebuilds/react-loadable
- danabramov 8y agoIf you don't do server rendering (which lazy doesn't support yet) then you can use them as a replacement, yes.
- ianschmitz 8y agoOne nice feature of react-loadable is that you can specify a threshold (300 ms by default I think) which is used to prevent rendering of the loader until after the threshold is passed so you don't get a flash of the loader. Users can perceive it as being slower if you have a quick flash of a loader then show the component. 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.
- hoppelhase 8y agoIs this planned for the Suspense API?
- danabramov 8y ago>One nice feature of react-loadable is that you can specify a threshold (300 ms by default I think) which is used to prevent rendering of the loader until after the threshold is passed so you don't get a flash of the loader. Users can perceive it as being slower if you have a quick flash of a loader then show the component. 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-16.html https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-... That's our end game.
- mcintyre1994 8y agoI was definitely mis-understanding functional components because I'd have assumed that memo was the default behaviour. Could anybody with more experience/knowledge suggest what sort of functional components you'd want to re-render if their props don't change? Cool that there's an easy way to get that behaviour now though! :)
- mbrowne 8y agoI did a good bit of research on the performance differences between different kinds of React components and back in February and submitted a PR to the React docs: https://github.com/reactjs/reactjs.org/pull/645 https://github.com/reactjs/reactjs.org/pull/645. If you want to read it (note: no one on the React team has reviewed this yet, but I was careful to confirm my findings): you can do so here: https://deploy-preview-645--reactjs.netlify.com/docs/optimizing-performance.html#functional-vs-class-components https://deploy-preview-645--reactjs.netlify.com/docs/optimiz.... 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.
- maaaats 8y agoI don't think before today it's whether the props change or not, but if the equal check should be deep or not.
- sophiebits 8y agoBy default, React doesn’t check if individual props are equal. This is for two reasons: 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.