18 ms·
React: Mixins Considered Harmful
- ludwigvan 10y agoI believe as time passes, we are moving away from the simplicity that made React win. Flux, Redux, higher order components generate too much complexity most of the time. React used to be simple, it still is, but the ecosystem and the mentality has gotten needlessly complex.
- danabramov 10y agoYou can use React without Flux/Redux if that works well for you. The “mentality” is just people solving their own problems in a way that makes sense to them, and sharing those solutions. As noted in the blog post, higher order components are not a React feature. And it is not related to Flux or Redux. It is just a thing you can do with components, like you can do it with functions. We think HOCs are a useful pattern so we explain it, but you don’t need to use it if you don’t get value from it. (We got a lot of value from using it.) That said if you have different solutions to the same problems that don’t suffer from the drawbacks of mixins, we’d love to hear them. This post is not there to force you to use HOCs. It’s for the people who had the same problems we experienced, tried to use mixins to fix them, and couldn‘t scale those solutions.
- zuck9 10y agoWhat I think OP refers to, is how there are so many different choices to do anything in the React ecosystem. It's cool that people share their work. But so many choices just cause decision fatigue. It's hard to have any kind of real-world usage from just React. You have to learn and use some kind of Flux, routing library, AJAX patterns for that Flux library, another library for <inputs> and <forms>, etc. If you want server-side rendering, server-side data persistence or user auth, which you will in real-world cases, you have even more things to connect. Also there aren't any free resources on the internet (that I could find) that teaches me how to put together a basic Twitter or Instagram clone using React + React ecosystem libs. No full-stack tutorials. Compared to Rails, React{ecosystem} is pretty hard to learn. Unless you're an experienced senior dev and understand all the different technologies deeply, you can't make any informed choice about what libraries to use. You just go and pick the most popular ones and later doubt your decision and think that you could be having an easier time if you had picked some other popular library more suited to your project. I guess most beginners just give up on React after trying a bunch of tutorials. I'm no Rails developer, but I guess even if you are a Rails developer with years of experience, you will find it frustrating to get started on React + ecosystem.
- danabramov 10y agoI agree that “getting started” experience is far from optimal. We take this feedback to the heart and want to improve this in the future. But how is this relevant to the post about mixins?
- zuck9 10y agoI see it went OT, sorry about that.
- tptacek 10y agoYou really don't need to learn some Flux to solve problems with React. React works fine without Flux, or really any formal data layer; you can comfortably use it simply as a really nice view library. I agree that people give up on React after tutorials that make them think about routing and Flux. It's a shame, because the core concept of React is incredibly simple, and anyone can pick it up in a couple hours. Flux is a useful, experience-based contribution and I'm happy to have it as an option. But it's heavily cargo-culted.
- quantumhobbit 10y agoThis, much more of this, please. I've been part of a small react project that was doing just fine without flux. Then the tech lead, a enterprise Java guy, decided we needed to use Flux because it was the "best practice". Problem was none of us understood Flux or how the project would benefit from it. It was pure cargo culting. Needless to say the whole thing became a huge mess as we spent all our time moving data to the store and back into the components. What is sad is that if the project had been allowed to evolve naturally, we might have ended up with a poor man's version of a Flux architecture, possibly even using Flux as a guide. Instead we had to force the project into a Flux pattern we didn't understand and wound up with a mess. Regardless, I have learned to associated the phrase "best practices" with some imminent cargo culting.
- acemarke 10y agoUh... on the contrary, there's a bunch of fairly in-depth tutorials out there. I have a number of them listed at [0] and at [1]. Also, I think a couple of the more commercial courses do that sort of thing as well. Wes Bos's Redux course builds a "Reduxstagram" app or something, Tyler McGinnis's "React.js Program" course builds up a couple specific apps, etc. [0] https://github.com/markerikson/react-redux-links/blob/master/react-tutorials.md#project-based-tutorials https://github.com/markerikson/react-redux-links/blob/master... [1] https://github.com/markerikson/react-redux-links/blob/master/redux-tutorials.md#project-based-tutorials https://github.com/markerikson/react-redux-links/blob/master...
- jswny 10y agoI feel like React is shifting in the same direction as the JavaScript ecosystem at large, which is unnecessarily complex, disorganized, and fast-moving.
- danabramov 10y agoCan you help me understand where React is shifting into a complex direction? To me, it looks like we are no longer recommending a complex pattern that we specifically supported in code (mixins), and instead recommend a simpler pattern that “just works” in JavaScript (higher order functions/components). If anything, we are shifting to a simpler direction, and it worked better for us. We are sharing the lessons we learned in the hope that you might also find them helpful. Sorry if they’re not!
- gedy 10y agoI think part of it is that not everyone is expert or familiar with functional programming (trained on OOP, etc) and it can feel overwhelming to many. "This is simpler - just another function" is somewhat subjective.
- danabramov 10y agoI believe this is exactly why we explain this pattern in the blog post in detail instead of just saying “this is simpler—just another function!” We are trying to both deliver a library that helps people ship quality apps, share our learnings about what worked, and what didn’t, and educate the community about the patterns that we found useful in our experience.
- gedy 10y agoI agree, mainly addressing the general vibe that React is complex - many folks have a gut knowledge of imperative that they lean on to make snap judgements about complexity, even when you explain it fairly clearly.
- Touche 10y agoThat's because people are using it for real things now, not just as a jquery plugin replacement, and it turns out that ignoring hard things doesn't make them go away.
- shados 10y agoYup. That's the point. The average frontend app really sucks. Error handling is poor, routing is bad, offline support is non-existent, it's buggy as hell, slow, etc. Now, not all apps need all of those things to be good, but they usually need some combination of those things. When you start making things "good", they're hard. Peanut Gallery Joe who learnt Rail and JavaScript over the summer jumping in this is not equipped to make a good app, and gets overwhelmed. Compared to writing "robust" applications in other ecosystems, the React world is really not that bad.
- spicyj 10y agoIf simple things were possible before with React, then they still are, and that's not changing. You don't need Flux and Redux a lot of the time; in my experience they're overused and React component state is underused. I agree the community mentality of adding lots of complexity on top is a problem. We're working on improving this, but if you have ideas I'd be interested to hear them too.
- nathancahill 10y ago> "in my experience they're overused and React component state is underused" Thank you, I've felt the same way. A lot of projects take "ALL STATE MUST BE IN THE STORE" to an extreme.
- sotojuan 10y agoWhich is funny because you'll never hear that from Dan or any other authors.
- nathancahill 10y agoikr
- eweise 10y agoIMO its no more trouble to put state in a redux store than in the component directly and doing so makes my components more consistent. I'm not a react guru though so maybe I'm missing something.
- nathancahill 10y agoEh, sometimes state isn't relevant outside of a component, so while you could put it in a store, it's possibly better to put it in the component. Single responsibility.
- brlewis 10y agoI bet React programmers who write a Mithril component or two would come back to React with more readiness to use component state. I don't have a plan for how you could use this idea to improve the community, though. As for the mentality of adding complexity -- are you sure that's a community problem? It seems a problem with programming in general. Advocates of adding complexity tend to be louder than advocates of using what's already there.
- adamnemecek 10y agoCheck out cycle.js. I haven't learned it quite yet but the promises seem really interesting. It's a fully reactive framework unlike react which is reactive only in view.
- danabramov 10y agoCycle is indeed interesting! React is not “fully reactive” by design, and does not plan to move further into the reactive direction. We think that React is well-positioned in the app to understand how to efficiently schedule work instead, which is something that would be harder for us to do with a reactive “push” approach. I think as time goes, it will be interesting to see how both Cycle and React evolve into different directions, and what different tradeoffs they might present and benefit from.
- jessaustin 10y agoIf you haven't looked at it in some time, Cycle.js has just really improved in the last month, an effort the devs are calling "diversity". Under the hood, that means RxJS is no longer a hard dependency, as a bunch of different reactive modules are now usable, including Staltz's new "xstream". Not having looked at Cycle in a few months, I'm not certain what all the particular changes have been, but I'm finding everything just seems simpler and more obvious. Admittedly, I am an RxJS novice, and some of the constructions I saw with that before just confused me.
- adamnemecek 10y agoThere has also been some perf work done recently it seems http://www.stefankrause.net/wp/?p=301 http://www.stefankrause.net/wp/?p=301 I have to look a little closer at the tests to be able to interpret the data but taking it on face value it seems like they are doing good work.
- rimunroe 10y agoJust a small point, but React has always had higher order components as long as I've been using it because they're just a subset of higher order functions. It's more of a feature of JavaScript than it is of React. Also, I've been encountering higher order components since I started on React two years ago I think. The definition of what constitutes a higher order component is very broad. I think that any render() method which returns a component would qualify.
- softawre 10y agoIf you're building a simple app, keep it simple (but, do you even need React then?). If you're building Facebook, bring on the strong typing and design patterns that facilitate building large javascript applications.
- smadge 10y agoI think React is moving towards a simpler abstraction. There is nothing simpler than a function with the type Model -> View.
- bjz_ 10y agoYup - trying out Elm makes you realize how much complexity is in the React + Redux stack that is not really needed...
- bschwindHN 10y agoTake a look at Reagent (ClojureScript library) for a breath of fresh air and simplicity.
- macspoofing 10y ago>I believe as time passes, we are moving away from the simplicity that made React win. Because every framework will handle small simple use-cases beautifully. When you include a codebase with thousands of lines of code, co-developed by many people, you can see where the pain points are.
- n0us 10y agoI personally moved all my projects away from mixins a while ago when I first heard they were deprecated. At first I was frustrated because of JS churn but this certainly was the right move. For anyone who is apprehensive, the shift in thinking from using mixins to HOCs was not so difficult even if it's initially puzzling. Quick edit: forgot to mention that this shift made my code way easier to understand in some places and thus the initial investment saves dev time in the long run.
- auvrw 10y agofrom the article > Let’s make it clear that mixins are not technically deprecated. If you use React.createClass(), you may keep using them. We only say that they didn’t work well for us, and so we won’t recommend using them in the future.
- rimunroe 10y agoI think around React 0.14, they announced that React's support for es6 class syntax wouldn't support mixins, and you'd only be able to get them by using the old .createClass method. I think they pointed out that they didn't see this as a big issue because mixins were a pattern they wanted to get away from anyway and saw better solutions to.
- deleted 10y ago[deleted]
- thatswrong0 10y agoI'm a fan of HOCs as well. My only problem with them is that I'm also a fan of shallow testing, and HOCs don't play nicely with shallow testing. I'm waiting on something like this (https://github.com/airbnb/enzyme/issues/250 https://github.com/airbnb/enzyme/issues/250) to get implemented
- coderzach 10y agoWhy not just mock the HOC to be the identity fn? `(Component) => Component`
- daliwali 10y agoIt doesn't fare well that a framework that is only 3 years old already has an extensive list of anti-patterns and tons of statements on what not to do. Also having to do manual performance optimizations using the framework is a hassle to application developers and can be a major pitfall (ex. PureRenderMixin, shouldComponentUpdate).
- nathancahill 10y agoNo, no, no. This is exactly what makes React so great compared to Angular (to pick one). There's One Way™ to do things correctly. Using anti-pattern "hacks" will work for a little bit, but in the long run come back to bite you as your software grows and scales. I've been using React for over 2 years now, and still refer back to that list when I feel like something isn't right.
- Bahamut 10y agoHuh? This sounds like it's more true of Angular than React - there is a widely adopted style guide, and well-known anti-patterns are very established. I don't get that impression with React.
- thejameskyle 10y agoAs a former Angular 1 user I have to disagree with you. There are many many ways of writing Angular apps and the community generally disagrees on what the best ideas are. Compare this to how people write React components, they all look pretty much the same no matter what application you are working on. Sure there has been some churn, but there are tons of helpful warnings when they have happened and the migrations are easy. The community is also on the same exact page when it comes to writing components. Outside of components there's a lack of the same cohesiveness with competing architectures. But the good ideas are rising to the top and the bad ones are fizzling away. I don't see it as a bad thing.
- nathancahill 10y agoI added "to pick one" because I don't particularly want to start a flame thread over frameworks. Everyone can choose their own tools for their jobs. However, to the point about style guide/anti-patterns: I guess we haven't been working in the same codebases.. I've worked on a handful of different projects and most have scope flying all of the place, with controllers and directives used interchangeably (not to mention factories/services/providers). But really my biggest gripe is the amount of logic that ends up in disparate HTML attributes. JSX is a much cleaner solution.
- hardwaresofton 10y agoDid facebook just rediscover that mixins are an anti-pattern? I would have expected them to know that going in, figured they had just thought it was fine as long as they convinced people to use them very sparingly
- zpao 10y agoNo we've known and said it for a long time but not very loudly. People haven't used them sparingly and they tend to infect a codebase. Now we're just making a more concerted effort to communicate more broadly that they can be bad.
- hardwaresofton 10y agoThanks for replying -- I assume in whatever planning/architecture meetings went on before react was released that this was a measured decision you all chose to take, weighing the potential dangers less dangerous than the initial usefulness. Is this assumption correct? If you could do it again, would you leave in mixins or would you keep them out?
- zpao 10y agoIt was the right decision at the time - it made React much more familiar for people at FB who were writing PHP/Hack (Dan called this familiarity out in the post). It also enabled some great things that are still awkward with other patterns - https://github.com/reactjs/react-timer-mixin/issues/4 https://github.com/reactjs/react-timer-mixin/issues/4 is an interesting case. That functionality is nice and elegant with mixins but not so with classes. I think if we had to do it again (and get to keep the knowledge of the last few years), we'd probably skip mixins. We'd surely do some other things differently too though :)
- rayshan 10y agoI see some React code using decorators but this article doesn't mention them. I'd love to get everyone's opinion on whether decorators are also an anti-pattern, even if decorators become a JavaScript standard.
- danabramov 10y agoSince they are not part of the standard, we are not going to take a stance on them yet. We do, however, think that it is very risky to adopt experimental language features unless they are very simple (like object spread operator). In my personal experience people often misunderstand how decorators work, and the tooling often breaks, so I would not recommend them with React yet.
- eiriklv 10y agoGreat post Dan. Just out of curiosity - what's your goto approach for replacing examples like the SetIntervalMixin (https://facebook.github.io/react/docs/reusable-components.html#mixins https://facebook.github.io/react/docs/reusable-components.ht...) with a HOC? I can't seem to find something that feels very elegant for these cases.
- danabramov 10y agoI’d probably create a class that lets me schedule intervals on its instance, and call `this.scheduler.dispose()` in `componentWillUnmount()`. I don’t think accidentally forgetting to dispose of it is a big problem as it’s easy to catch in a code review. But if it concerns you, HOC could work for this as well. In the future, we might build some helpers for this into React itself.
- eiriklv 10y agoYup - that's more or less what I've ended up with. Just wanted to hear you if you had a better solution at hand. It's pretty much an edge case example, as 99% of all this stuff fit perfectly into the HOC way of thinking. The remaining cases won't add any more context/complexity than using mixins do anyway. Thanks for all your hard work!
- evan_ 10y agoYou could write a pretty trivial component which takes an interval and method as props, and sets the interval in componentDidMount and cancels it in componentWillUnmount. It probably doesn't make sense to do a timeout that way...
- kimmshibal 10y agoI ported my app from React to Vue in 2 days. Couldn't be happier
- danabramov 10y agoThat sounds great. Evan put a lot of effort in Vue, and it’s satisfying to see it paying off! While this is very tangential to the article, could you elaborate on what you struggled with in React? We are always looking out for things we could improve.
- bcherny 10y agoImplementing mixins correctly in JS (which React does not) is already a well explored problem space. I like https://leanpub.com/javascript-spessore https://leanpub.com/javascript-spessore for great explorations and derivations of various mixin patterns. It's not that mixins are bad in general, it's that React doesn't implement them well in particular.
- danabramov 10y agoSure, it may be React’s mixin implementation that is subpar. However we noticed we didn’t need mixins (of any kind) with the patterns described in the post. Just components and functions turned out to be enough for our needs, and this is why we wrote this post. I think the post specifically addresses this point: >This doesn’t mean that mixins themselves are bad. People successfully employ them in different languages and paradigms, including some functional languages. At Facebook, we extensively use traits in Hack which are fairly similar to mixins. Nevertheless, we think that mixins are unnecessary and problematic in React codebases. Maybe I should have highlighted that they can work well in JavaScript too—we just didn’t find a good use case in React apps at Facebook.
- bcherny 10y agoThe thing is, mixins are a pattern, and patterns are interchangeable. So you can use composition, single inheritance, multiple inheritance, and mixins interchangeably in most cases. It's not that you need a particular pattern, it just might be easier to express a certain idea with a given pattern. I agree with you that composition is easier to understand, since component APIs are well defined. For large teams like those at FB, this simplicity can be a big win.
- spicyj 10y agoCan you outline the biggest problems with React's mixins? I haven't heard this complaint before.
- bcherny 10y agoI'm sure you and @danabromov have more thoughts on this, but I would generally constrain the mixin system more: - Don't let mixins call setState() directly; otherwise, it can be hard to track down what mutated the state. Have a well defined, canonical way to update state (proxy methods on the main component? Flux-style actions?) - Don't let mixins define a render() method; this is the component's responsibility - Separate mixin state from component state; mixins should not be able to see each others' state, and the component should not be able to see its mixins' state. Have a special API for a mixin to get its component's state (eg. this.getComponentState()) - Use vanilla ES6 mixins (class C extends mixin(A, B)) for interoperability with other libraries Again, Spessore is a great exploration of how to implement these sorts of constraints.
- BinaryIdiot 10y agoBut mixins are so easy and are used in thousands of JavaScript libraries. Seems odd to deprecate their usage in React; why wouldn't you embrace a typically used construct in JavaScript? The syntax without mixins just seems overly complex. I mean sure it's still simple but more complicated than before and certainly not intuitive (in my opinion anyway). I just started exploring React not long ago. It's interesting but I'm not sure it's my cup of tea just yet but most of the issues mentioned exist everywhere with JavaScript because, well, it's a dynamic language. I would suspect many of the issues lie outside of using mixins and more of how everything is architected but without seeing their codebase I don't actually know that. I just know mixins can be used, relatively easy, and cleanly as long as your design is appropriate for them.
- danabramov 10y ago>Seems odd to deprecate their usage in React; why wouldn't you embrace a typically used construct in JavaScript? Because we already did embrace it, and we found that it was a mistake. I believe that the article addresses why mixins didn’t scale well in our React codebases. We have written a ton of React code and wanted to share our experience. It seems quite normal to me that our experience might not match experience of other JavaScript users. React offers a component model based on functional composition solution that was not quite common in JavaScript until very recently. Paradigms are much more fundamental than languages. We found that, with React’s paradigm, in our experience, mixins were unnecessary. For sure, your mileage may vary. >most of the issues mentioned exist everywhere with JavaScript because, well, it's a dynamic language You might not believe me, but these issues had much less of an impact on us with React’s component model. And even less so after we started using gradual static typing with Flow (http://flowtype.org/ http://flowtype.org/). >I would suspect many of the issues lie outside of using mixins and more of how everything is architected but without seeing their codebase I don't actually know that. I have been employed by Facebook for just a few months. I have written a few relatively complex React apps myself before. I didn’t see much of a difference between the mixins I wrote previously and mixins I saw at Facebook. In my view, both mixins I wrote and mixins I saw at Facebook introduced similar problems to the respective codebases. It’s great that you know how to use mixins without shooting yourself in the foot. This is a rare gift in my experience. Most people (like me) will overuse them because they’re too powerful. On the other hand, components are limiting enough that even people like me can write code that is easy to maintain in the long term. >The syntax without mixins just seems overly complex. I mean sure it's still simple but more complicated than before. What syntax are you referring to? I don’t think there was any new syntax in the article. The only challenging part might be the idea of a higher-order component, but this is not even a React feature. It’s the way JavaScript works: you can create functions and pass arguments to them. It turns out that we could solve one of the use cases for mixins with vanilla JavaScript constructs and without the need for a complex mixin system. I think you might be missing the point that we have seen quite a bit of React apps being developed. Some of the things we say might be counter-intuitive but they come from Facebook’s extensive experience of using React (more than 20,000 components). So when we’re saying something, it is not theoretical or out of spite. We are trying to share our experience with you, in the hope that you might find it useful not to repeat our mistakes.
- ThePhysicist 10y agoThe decorator-based approach sounds interesting, but (in my understanding) it will require moving the data fetching logic away from the main component into the decorator, which also creates a level of indirection that is intransparent to the component user, and I imagine stacking several of these decorators on top of each other should provide plenty of room for unforeseen side effects as well. Personally, I think almost all components should be "dumb": They should just receive the stuff that they display as properties from their parent components and report changes back through callbacks. They should not perform any "controller logic" beyond form validation and input serialization. Only a few components at the top should be responsible for fetching and distributing resources from the backend. Typically, it should suffice to have an "Application" component that takes care of fetching stuff that every other component should see (e.g. data about the user), while components one level below the application should fetch stuff that is specific to the given page/view that is being displayed. Unfortunately, compared to the humble beginnings a few years ago I feel that the whole React.js stack gets more and more bloated these days. As an example, managing state through Redux requires writing actions, reducers and implementing a subscriber pattern in my components, just to fetch some data from the server. I mean, if we're writing a version of "Photoshop" for the browser this level of complexity might be warranted, but in most cases we just want to fetch some JSON, display it nicely formatted to the user, let him/her click on it and possibly send some data back. If we need 500 kB of Javascript libraries to do that while having to patch/reinvent many other things that we took for granted before -like simple hyperlinks (I'm looking at you, react-router)-, chances are we're doing it wrong.
- lopatin 10y agoData declarations via decorators for use by some data fetching layer sounds like exactly what I want. > creates a level of indirection that is intransparent to the component user, and I imagine stacking several of these decorators on top of each other should provide plenty of room for unforeseen side effects as well. Unforseen side effects ... that sounds scary! Though vague. Imagine there is some controller component (a currency conversion widget) and we're adding a dependency on "/exchange_rates.json". If we could add a hypothetical @getJSON('/exchange_rates.json', 'rates') at the top of the component declaration to make sure the "rates" prop is always either missing (loading) or present (successfully returned data, or an error response), that sounds great. It only takes ownership of one prop. Stacking decorators would work nicely. Am I missing the glaring avenues for unforseen side effects?
- Double_Cast 10y agoSo uh, HOC's are basically monads. Right?
- danabramov 10y agoI think the intuition might be a little bit related but AFAIK monad is a very specific thing (can “lift” something and map functions over it, or at least that’s what I remember from a monad tutorial), and HOCs are different (they just wrap components). “Decorator” might be a closer pattern. I would say HOC is more like a regular higher order function... which is why it’s called this way. :P
- smadge 10y agoI agree, a "higher order component" just isn't a monad. A HOC is just good old fashioned object composition. I think you are right to call it the decorator pattern. It annoys me how React ,and in general the entire javascript ecosystem, reinvents the wheel, then gives their invention another name.
- danabramov 10y agoIt’s not quite object composition though. We are not forwarding any method calls or containing the instances. HOCs are much closer to functional composition than to object composition.
- pka 10y agoNo no, just higher order functions. They don't have join and return.
- Cshelton 10y agoFor those of you complaining about "javascript complexity": I think one of the biggest misunderstandings about JS and a large portion of the community complaining about "churn rate", is that JS does not have a churn problem, it has an inexperienced developer problem. Which is not to say that is a bad thing, JS/web is the first language for MANY programmers now. When you get stuck on learning this framework vs that framework, or a antipatterns within a framework and "complexity" being added to a framework, take a look back and understand the WHY first. Many ideas and the fundamental design of React are not new. Infact, they are very old, even before there was such thing as the internet. Functional programming patterns, also very old. Immutability, a very old concept. Composing rather than inheriting, old concept. Eliminating all side effects (through immutability and composition), very old concept. The idea of a "higher order component", is not new, nor does it have any direct relation to React. It is a design pattern. This article is simply teaching you a design pattern that aligns with the design patterns React was built upon and works very well. Instead of complaining about React and "added complexity", I encourage you again, to ask why. Learn why this blog post, from the React core team, recommends doing it this way. It is in no way a requirement. React is just a tool. It is just Javascript. It is just programming. Welcome to the development world. Also, understand the problems you are trying to solve. Facebook uses these design patterns because they have thousands of components at a massive scale. The majority of users will not be working on something of that size. Don't feel like you have to use everything that comes out and is available in the React ecosystem. Infact, I would urge you, never start using something UNTIL you come across a problem and need to find a solution. It is a common thing for inexperienced developers to feel the need to incorporate everything they have read about, when they are using them to "solve" problems they don't understand, nor even have. This applies to problem solving in general, not just React, not just programming. TL;DR Understand WHY something is used in the way it is before throwing it out as "too complex". Don't solve problems you do not have, until you need to actually solve them. If you do use a pattern/tool/etc., understand the WHY. (Don't use Higher Order Components or redux if you have not had the need for them and do not understand the problem they solve.) Also understand that many design patterns coming to JS are not a result of JS churn, they have been around a long time and have a very good reason for existing. JS churn is not real, it is a misunderstanding of using a solution in a world that has many solutions available.
- tlrobinson 10y agoI thought this was pretty well known by now, given the lack of mixin support in ES6 React components (and functional stateless components), but this is a nice summary of the problems and solutions.
- wmccullough 10y agoI'll likely catch some hell, but there's a reason mixins are considered an anti-pattern in most languages...
- spicyj 10y agoYup, no news here. For people who already know that, this was designed as a post with specific examples that tend to pop up in React codebases and advice about how to migrate away from them.
- mikegerwitz 10y agoI'm not familiar with React's mixins, but I get the impression from the suggestion to use higher order functions that it doesn't allow overriding methods from other mixins. E.g. Scala's concept of stacking. For those interested in the concept in JS, I implemented a full trait system in GNU ease.js designed around Scala's approach, with support for stackable traits. The system also supports protected/private properties and methods, which can also be taken advantage of in traits to provide public and protected APIs, and keep state encapsulated in traits. I don't have documentation available yet (soon), but I do have a great many test cases that demonstrate various aspects: https://www.gnu.org/software/easejs/#traits https://www.gnu.org/software/easejs/#traits https://www.gnu.org/software/easejs/news.html#d9b86c1 https://www.gnu.org/software/easejs/news.html#d9b86c1 Hopefully others find this to be interesting even if they don't agree with ease.js itself.
- anaclet0 10y agoComing from ember 1.x, mixins are pure evil
- iandanforth 10y agoI worry this suggests an opposition to inheritance in general. Sharing code through class hierarchy is incredibly useful and common. I'd hate for ES6 to add decent classes and then have React push people away from 'extends'. But perhaps I'm reading too much into this.
- danabramov 10y ago>I worry this suggests an opposition to inheritance in general. Sharing code through class hierarchy is incredibly useful and common. This is indeed opposition to inheritance in general, precisely because we tried it, and it doesn’t work great in React apps. React has a strong composition model that does not need inheritance. https://discuss.reactjs.org/t/best-practices-for-extending-subclassing-components/1820/2 https://discuss.reactjs.org/t/best-practices-for-extending-s... Of course you are free to use inheritance for other purposes. (Or even React components if you insist.) But as the team behind this library, we strongly suggest you to use composition instead of inheritance when defining React components.
- Bahamut 10y agoI would add that there seems to be a push against inheritance in general with UI components in the frontend web app world. React clearly is designed against using it, and same thing with Angular 2 (inheritance does not play well with decorators, which are metadata on specific component classes). I don't think we really see any modern UI library/framework adopting inheritance as a valid pattern at the component level, precisely due to the problems of leading developers down the path of creating potentially incorrect abstractions & being too painful to fix when UI can potentially change quite a bit structurally. In addition, anything a user can accomplish with inheritance, a user can also accomplish with composition, but while retaining flexibility, so when considering how much the UI layer can change in an app, one generally wants that flexibility. Inheritance is more useful when creating low level abstractions or maybe wrappers around such, but should generally be avoided when it comes to consumption for higher order constructs because of the complex chains involved. * This is what I have found at least - perhaps I'm making some incorrect points. If so, I'd like to know why I'm wrong here, since these are just conclusions I've drawn from experience so far.
- janci 10y agoI like how core features of React are being considered harmful. First it was component internal state, now it's mixins and next thing will be the lifecycle methods. React components will then boil down to pure render functions. React will then be replaced by simpler VirtualDOM implementation. JS function declaration boilerplate will be removed from render functions, so they will be more HTML with some JS as the other way around. Also they will be called templates. We are getting back to good-old-days PHP-style webcoding, but with few HUGE improvements. 1. no globals, mostly pure functions 2. no business logic in templates, but in easy-to-reason-about redux-style state reducers 3. client-side rendering / isomorphic apps possible
- jacobr 10y agoComponent state is hardly considered harmful. What has given you that impression?
- juanger 10y agonot exactly harmful, but in the docs they promote stateless functions by saying: "In an ideal world, most of your components would be stateless functions because in the future we’ll also be able to make performance optimizations specific to these components by avoiding unnecessary checks and memory allocations. This is the recommended pattern, when possible." See https://facebook.github.io/react/docs/reusable-components.html#stateless-functions https://facebook.github.io/react/docs/reusable-components.ht...
- petewailes 10y agoThat's more because most components are render-focused, which means they're more concerned with props than with state. Of course, a particular render component might also have its own state (imagine a list with pagination for example), which isn't required by any of its parents or siblings. However, state is something on the whole that's required more often higher than lower in your architecture. I'm pretty sure that's what they're talking about here. Hope that helps.
- 10y ago
- abalone 10y ago"Considered Harmful" Essays Considered Harmful: http://meyerweb.com/eric/comment/chech.html http://meyerweb.com/eric/comment/chech.html
- danabramov 10y agoI don’t think there’s anyone writing Considered Harmful articles who hasn’t ready that essay but thanks! ;-)
- pjmlp 10y agoApparently React is already moving from "Technology X will solve all problems" to "Technology X considered harmful" pattern.
- sergiotapia 10y agoReact dropping mixins is the #1 reason why I stopped using Meteor. Sure Meteor has Blaze, but nobody uses it. Before we had a nice mixin called getMeteorData: ``` var HelloUser = React.createClass({ mixins: [ReactMeteorData], getMeteorData() { return { currentUser: Meteor.user() }; }, render() { return <span>Hello {this.data.currentUser.username}!</span>; } }); ``` Short, simple, you knew exactly what it was doing without breaking your wrists. Now it's some create container lunacy that brings no benefit to most projects except dogma "properness" - the developer UX is just fungled beyond belief and it makes me so sad that Meteor lost so much. I guess my gripe in general with Javascript now is how complicated simple things are. It's entire ecosystem is intertwined with complexity and verbosity. I wonder if typescript alleviates some of these pain points.
- bcherny 10y ago> I wonder if typescript alleviates some of these pain points. TS :> JS, not <:. What specifically are you hoping TS addresses?
- tlrobinson 10y agoI was going to sketch out a higher order component for you that does the same thing but it looks like they've already implemented that: https://atmospherejs.com/meteor/react-meteor-data https://atmospherejs.com/meteor/react-meteor-data I guess this is the "create container lunacy" you're talking about? I'm not sure what's so horrible about it, especially if you enable decorators in Babel (admittedly non-standard syntax but it works great): @createContainer(() => ({ currentUser: Meteor.user() })) export default class Foo extends Component { return <span>Hello {this.props.data.currentUser.username}!</span>; } This is basically how Redux's React bindings works too. Is it really just the syntax you're upset about, or am I missing something?
- danabramov 10y agoYou don’t even need that syntax. (Please don’t use decorators in examples, they are not part of the language yet. This is super confusing.) function Foo(props) { return <span>Hello {props.data.currentUser.username}!</span>; } function getMeteorData() { return { currentUser: Meteor.user() }; } export default createContainer(getMeteorData)(Foo) Why do you see this as “lunacy” compared to mixins?
- leogcrespo 10y agoAwesome post Dan, thanks for writing and sharing! One thing caught my attention: >At Facebook, we extensively use traits in Hack which are fairly similar to mixins. Nevertheless, we think that mixins are unnecessary and problematic in React codebases. Here’s why. >Mixins introduce implicit dependencies >Mixins cause name clashes >Mixins cause snowballing complexity When I read these three reasons, I actually felt identified with them even outside React, since these as pretty generic problems in "mixin-like" cases that I've seen, for example Ruby modules. So it got my attention the fact that you're (at Facebook) using Hack traits successfully. Why is that? Are any of those reasons you stated not true with Hack traits? (Maybe you don't have knowledge in Hack though, but any high level conceptual idea may help). Again, awesome post!
- asQuirreL 10y agoTraits and mixins are different. A trait/interface/protocol doesn't generally contain implementation, and when it does, it is based only on other methods in the trait (for things like default implementations), whereas mixins are just fragments of a class implementation with potentially arbitrary dependencies on methods. So traits document the dependencies that mixins make implicitly. Traits in typed languages can only cause name clashes if two methods in different traits have the same name and the same type signature. This is immediately obvious, and the compiler will warn you so you can fix it there and then when you try and implement them both for one class. (It also brings into question whether there should be another trait to hold that shared method). The snowballing complexity that is mentioned stems from all those implicit dependencies: There's no way of knowing what they all could be in a nest of related mixins, whereas the corresponding traits document it and provide a map, of sorts.
- leogcrespo 10y agoThanks for your response. I can see how type checking helps with that in Hack, that makes a lot of sense. Guess that in the case of Ruby for example we'd still have the same disadvantages as in JS right? Since there's still the possibility of calling methods in other modules and even in the class where the module is included, since that is discovered at runtime and you don't have any hierarchy that restricts who can call what.
- jameslk 10y agoThat's too bad, mixins were simple to grasp and worked really well. The oft suggested alternative to mixins is higher order components. Here's one of my favorite quotes[0] on the matter: > You lose so much with [higher order components], especially with es6: > You lose the (original) class, and with it, the ability to compose it, to extend it and …. reflection. All your components are [the higher order component]. For example, you cannot rely on the Class.name in es6. > You lose the ability to extend the component and expose extra members. Your higher order component will not ‘pass’ that through. > The above two basically renders the ability to compose several decoupled and agnostic one to the other “higher level components” impossible. > It is verbose and non-declarative , and basically much less readable and maintainable. If there's a better pattern than mixins, I would say its traits[1]. For some reason, I don't find it used much often in the wild. I'm not sure it would be practically applied to React anyway without ending up with mixins again, but at least the concept would be clearer: there should be no shared state and dependencies are explicit. 0. https://medium.com/@danikenan/you-lose-so-much-with-your-solution-especially-with-es6-bcf4fdad40be#.u0e6qabr1 https://medium.com/@danikenan/you-lose-so-much-with-your-sol... 1. https://en.wikipedia.org/wiki/Trait_%28computer_programming%29 https://en.wikipedia.org/wiki/Trait_%28computer_programming%...
- Vilkku 10y agoFrom the article: > Let’s make it clear that mixins are not technically deprecated. If you use React.createClass(), you may keep using them. We only say that they didn’t work well for us, and so we won’t recommend using them in the future.
- danabramov 10y ago>the ability to compose it, to extend it and …. reflection In our experience those are precisely the things that can turn codebases into a mess. It’s great that you can manage the complexity from inheritance and reflection, but in our experience most people had problems with these patterns (me included). On the other hand, we found that React composition model is enough to express everything we needed in the apps, and we didn’t miss inheritance or reflection.
- rukuu001 10y agoDoes that mean the LinkedStateMixin is going away?
- danabramov 10y agoYes, eventually.
- coltonv 10y agoSo there are a lot of features in React that are basically getting deprecated, like createClass in favor of ES6 components, mixins, etc. This is good that you guys are learning as you go, my question is will you ever release a version of React, possibly spin React off into a version which supports deprecated APIs and a version that doesn't and is therefore smaller, faster, and easier to maintain? Eventually you could drop support entirely for the deprecated feature. That would be the best response to this IMO.
- danabramov 10y agoWe are not deprecating `createClass()` yet. When we do, we will keep it for another major version (just like we always approached deprecations) and then move it to a separate package so only people who really want it would use it.
- coltonv 10y agoYeah I was just using createClass as an example of a feature that's not strictly necessary and could be removed to slim up the library. Thanks for responding! Any idea when you will be trimming stuff like that out? Do you think you will you ever remove mixins?
- danabramov 10y agoWe don't need to remove mixins because that's one of the biggest reasons people use createClass(). So it's enough to just separate createClass() and then we wash our hands, and it lives its own life. We won't use it but others are free to if they like it. No specific timeline but we might I'd say within half a year is likely.
- skwosh 10y agoIt's not clear to me why (in the pattern presented) the decorators don't return a subclass (which would preserve the dynamic and static properties and methods, etc). Instead you get hacks like `hoist-non-react-statics` to copy them over manually. For context, the article advocates the following: import GlobalClass from 'global-class' const decorator = SuperClass => class extends GlobalClass { render() { return <SuperClass {...etc}></SuperClass> } } This can be rewritten to remove the fixed dependency on `GlobalClass`, while preserving the underlying type: const decorator = SuperClass => class extends SuperClass { render() { // const SuperClass = super.constructor // if you want to be less explicit... return <SuperClass {...etc}></SuperClass> } } The only requirement is to maintain the contract outlined by the `SuperClass`, but that's what `super` is for. (By that I mean e.g. that `componentDidMount` should't be overwritten without also calling super.componentDidMount() before/after). Returning a different kind class entirely limits the utility of the pattern in general (IMO), and you lose the nice function-composition-like behaviour provided by `super.method`.
- danabramov 10y agoIn our experience inheritance causes a lot of hard-to-find issues, and muddles boundaries between component concerns. Some of the same problems I described we had in mixins also apply to inheritance. >and you lose the nice function-composition-like behaviour provided by `super.method`. We found this to be an anti-pattern. It’s easy to get lost in virtual calls across hierarchy, and people are going to create virtual methods (and override them) if you allow it. >Instead you get hacks like `hoist-non-react-statics` to copy them over manually. An alternative is to just not put static methods on component. It’s not such a useful feature.
- digisth 10y agoMixins have their place, but perhaps we are at the point where we need general advice (like the class "Prefer composition over inheritance") for mixins ("Prefer traits over mixins"), especially as there's a good analog between the two. Matthijs Hollemans wrote an article which argues for that as well: http://matthijshollemans.com/2015/07/22/mixins-and-traits-in-swift-2/ http://matthijshollemans.com/2015/07/22/mixins-and-traits-in...
- deleted 10y ago[deleted]
- nikki93 10y agoWhy not just prototype inheritance with multiple inheritance? Like Self. The class-instance duality is removed then, and everything is just an editable object. This always made the most sense to me. Then just having the 'universe' be a map of id->obj with prototype inheritance, then editing the universe being reduxy and just a reduce over the objects, with the reduce polymorphised over the object's inheritance (this is the benefit of OO, really, not mutable update)--brings wins of functional, prototype, OO all together.
- charlysisto 10y agoIt's funny to see in the life cycle of every new language/framework in the block the rediscovery of good architectural patterns that can be summed up in one sentence: - inheritance & mixin bad / composition good. Good article nevertheless.
- vog 10y ago> inheritance & mixin bad / composition good This wisdom is at least as old as the classic GoF book [1] which was published in 1994. Many of their patterns can be summarized as: "Favor 'object composition' over 'class inheritance'." They also give a pretty simple, compelling reason for that: It is just a direct consequence of the even more fundamental principle: "Program to an interface, not an implementation." [1] Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides): "Design Patterns: Elements of Reusable Object-Oriented Software" https://en.wikipedia.org/wiki/Design_Patterns https://en.wikipedia.org/wiki/Design_Patterns
- charlysisto 10y agoI would argue that the more intuitive principle behind composition is the "Single Responsibility" one. Although it is correlative to the idea of 'program to an interface' (aka don't mingle with the state from the inside of an object that is not for you to do) I find it easier to grasp. While i'm at it I'll add that the main reason SRP is so important is because it limits combinatorial explosions of state, so you can keep control, test and reason about it - incidentally the main idea behind the success of React.js
- tomjen3 10y agoI find that inheritence allows me to save a ton of code, but using it widely does mean you need the ability to refactor, which isn't hard in Java or C#, but can be more of a pain in languages like Ruby.
- robmcm 10y agoinheritance is very hard to comprehend at a later date, traversing though sub/super class hierarchy, overrides and super calls is incredibly painful. You often end up with a subclass that may be thousands of lines in length if you consider it's flattened definition.
- enugu 10y agoRacket has classes as first-class values. So a mixin is a function from one class to another. This seems similar to higher order components solution. https://docs.racket-lang.org/guide/classes.html?q=mixin#%28tech._mixin%29 https://docs.racket-lang.org/guide/classes.html?q=mixin#%28t...
- danabramov 10y agoSimilar but the big difference is the wrapping component does not extend the wrapped component. It uses React component model for composition.
- welder 10y agoFrom my extensive experience using Backbone, Angular, and now React: React and SPAs Considered Harmful I keep seeing dependency bloat, over-engineering, unnecessary complexity, all with SPAs not providing the basic things Django/Flask do easily. A good explanation here: https://medium.com/@wob/the-sad-state-of-web-development-1603a861d29f https://medium.com/@wob/the-sad-state-of-web-development-160... If you're going to use React, use it on one page don't make your whole site/app a single page app.
- tjholowaychuk 10y agoI kindddd of feel this way about the "global" context as well, but it's one of those sketchy-yet-handy things haha. Though beyond react-router and redux using it I haven't touched it personally.
- Waterluvian 10y agoI will fight hard to never use globals or Singleton's. It makes my code conceptually way more obvious but sometimes the boilerplate is just wild to pass things like eventemitter around
- jpsierens 10y agoThe higher order function example in ES6: https://jsfiddle.net/jpsierens/obgh1uc7/2/ https://jsfiddle.net/jpsierens/obgh1uc7/2/
- udarkness 10y agoSeems to be that the harmful part of the code is actually the OOP. The solution they provide is not a direct attack vs mixins (composition, multiple inheritance), instead they propose to use functions instead of methods but keeping the root of the problems (methods), they may notice in the future that the classes will bring the same issues (the parent can also have a method with the same name...). Notice that the key solution is to use functions (pure, deterministic). While react is a good improvement to remove states, it still promotes objects that are still holding states. I hope they can get more advise from their haxl team :)