Hacker News new | past | comments | ask | show | jobs | submit login
React JS Best Practices (siftscience.com)
252 points by lopatin on May 9, 2015 | hide | past | favorite | 89 comments



> Flux is also quite verbose, which makes it inconvenient for data state, state that is persisted to the server.

We felt the same way, until we moved away from Facebook's Flux implementation and adopted Flummox[0]. It's singleton-free, so we gained isomorphism for our application with only a tiny bit of extra work, and it hides away the dispatcher (unless you need it, which we haven't despite having over a dozen stores, tonnes of actions and a large number of components).

With Flummox making it so easy, we put all state into a store. This allows us to save application UI state to localStorage, bootstrapping the app into the same position the user was previous, with again no extra effort on our behalf. It's well worth checking out!

[0] http://acdlite.github.io/flummox/


Flummox is incredible, and pretty much the first thing I point beginners to after they've learned the basic concepts of flux (I don't even show them Facebook's implementation because it's actually pretty poor and relies heavily on singletons and interacting directly with things that should be implementation details like the dispatcher)


Gosh yes, Facebooks implementation doesn't really do the whole idea justice to be honest. Alt and Flummox are much nicer, but I found Flummox far easier to use; one of the few libraries that seems to strike the balance between minimalism and features. I'm definitely impressed, and it was a super easy sell at work to move to a "three tier" architecture, because two of those tiers are the same code base with Flummox and React!


I wonder how everyone takes care of error handling in Flummox (or Flux in general)? Would you also trigger an action, then wait for the store to set some sort of error state?

Basically, how would you migrate the following code to Flux:

  click() { doAction().catch(err => showModal(err)) }


Great question! Actions should be thought of as a mapping between some mechanical UI event (typing in a form, clicking on a button) and an event with some meaning in your application ("user typed a hacker news comment", "user submitted a reply to this comment with this text"). Whatever your application data store abstraction is, it should be responsible for taking that meaningful event and figuring out what to do with it (check to see that the message isn't empty, check to see that the comment was persisted to the server).

Actions describe things that happened in the world and the role of your store is to figure out if that thing that happened is valid or not, and pass the necessary data to components listening for changes.


Thanks for your explanation, that makes sense theoretically but... could you provide a code example for how this breaks out in practice?


I guess what s/he meant was having something like this in the store:

  handleComment(comment) { 
    if (comment === '') this.dispatch('comment-error', 'empty')
    else svc.send(comment)
            .then(() => this.dispatch('comment-success')
            .catch(err => this.dispatch('comment-error', err))
  }
The view/controller (or whatever it's called in React) will then listen to the events and set its state accordingly so that the UI can be re-rendered.

It does look quite complicated compared with typical error handling code. Not sure if I misunderstood something or whether this additional layer of message dispatching is worthwhile in most apps.


What does isomorphism mean here? I know what it means in mathematics, but the explanation in flummox site does not compute for me.


It's a term used to refer to applications that run some of the same code client-side and server-side. See: http://isomorphic.net/


In React / Javascript land, isomorphism means, "the same code is used to render on the server and in the browser"


I really really hope the JavaScript redefinition of this word dies out. Please just make a new word instead of butchering a perfectly well-defined one.


It's using the completely correct biology usage: "a similarity of form or structure between organisms"

Thinking it only refers to one field and is wrong - when the usage is totally correct (and very applicable) just makes you sound snobbish... and foolish.


I don't disagree, I come from a maths background so it's a bit weird too; however, I'm yet to see a decent alternative and it's rather entrenched now. It's not a good descriptor however: using the word with non-tech product owners makes their eyes glaze over, so I'd love something better but am yet to come across it.


Oh holy shit I just moved my app off of reflux and on to flummox and wow! Much better


I'm also curious to hear why you like Flummox better than Reflux. I'm using Reflux now, and haven't hit any pain points, which I can't say the same about some of the other Flux implementations.


When I started investigating isomporphic strategies with Reflux I stumbled upon this thread (https://github.com/spoike/refluxjs/issues/144) which made me realize that if I didn't switch quick I would have some terrible technical debt on my hands in the coming months. I started looking for alternatives and found Flummox, which is lightweight, isomorphic, and written for the future via ES6-7 features like async await and classes. (Once you start using ES6 classes with ES7 classProperties turned on via Babel -> stage 0 you'll never want to go back to the old way of writing things.)


Well pretty much Flummox is ES6-ified Reflux, no big differences in functionality...


What would you say the major differences are with Flummox? It looks pretty straightforward but Reflux seems pretty lightweight as well. Just trying to figure out if it's worthwhile to switch an early stage project over.


I would say that Flummox is a slightly more verbose Reflux, written in a way that is somewhat more future proof and adaptable to change.


For the past one month, I've been working on an app in Reflux. If the benefits are significant, I'd surely look at switching to Flummox. Care to point out how the switch has been useful to you?

Thanks!


I like very much that the API is more "standard" (reflux, imo, has some strange patterns) -- also, due to the ability to instantiate every aspect of the pipeline, you get isomorphism for free, and testing is much, much simpler.

Also, can't hurt that the library was designed and implemented in ES6, which is what I've begun moving our architecture towards!


This is probably obvious but why is the existence of singletons what destroys "isomorphism"?


Because that singleton will serve multiple requests on the server, requests from different users. Singletons are more okay on the client because you know you'll only serve one user, so the singleton can make that assumption as well. But that doesn't work on the server, since the singleton is serving more than one user.

You can still use singletons on the server, but you have to pass the current user id to every method/event on that singleton. And that ends up being quite annoying.


Ah, I see. Thanks.


On the serverside, your stores should not be singletons (shared between all requests) but in request scope (one per request). Otherwise users will be reading eachother's data.


Has anyone built their app using ES5 and Flummox? The Flummox documentation is sparse to start and is completely devoid of ES5 examples.

Edit: grammar.


I struggled the same with another ES6-first library. The best way to convert those to ES5 is via copy / pasting the code in https://babeljs.io/repl/. After a while, you'll quickly learn the syntax and the code will come naturally.


Why not write in ES6 and transpile downwards to ES5? You're just fighting the direction of the wind otherwise. ES6 feels much, much nicer to work with in nearly all ways.


We rolled our own Flux library before they published any code, dodging singletons and gaining mock-free testability. I just re-wrote it, but will check Flummox out.


I had been using reflux when trying out react native. This actually looks nicer than reflux, i think i'll check it out :)


Having just started using React for a new project, I absolutely love it.

This new project uses a Rails backend, with React allowing the web to act the same way as any other client (iOS app, Android app etc), and it's so productive to work in.

Pretty much decided I won't be writing a web app any other way for any future work.

These best practices look pretty good, though my advice to any beginners would be to not get too bogged down in worrying whether you're doing things 100% right as React can be pretty forgiving in refactoring later on.


>Pretty much decided I won't be writing a web app any other way for any future work.

Careful what you wish for!


"React can be pretty forgiving in refactoring later on."

>>> So true


One of my initial problems with React & CSS was styling :hover etc. For now, Radium [0][1] solves this problem, but IMO as a community we're still trying to figure out all the best practices and patterns, when it comes to building isomorphic webapps (or webapps is general, since React introduces new way of building apps and I'm sure that's just the beginning).

[0] http://projects.formidablelabs.com/radium/

[1] https://github.com/FormidableLabs/radium


Why did you want to do it this way, rather than using CSS classes and a stylesheet? I've read the Radium intro and I still don't get their use-case. To me it feels like a misunderstanding of CSS, so inlining it in the component makes sense to the programmer.


This is a great question, I used to think exactly the same until I became enlighten ;). Well OK, to be honest I'm still not entirely happy with how things are modularized, but I see advantages. This is a very good presentation which explains key ideas: https://speakerdeck.com/vjeux/react-css-in-js

Understanding the problems mentioned in the slides was literally eye opening. I was already trying to solve the problems with CSS, without fully realizing that I'm solving them. For example, my "solution" to namespaces was creating a naming conventions for all classes/IDs, like ".header-search-box-button" and this approach becomes PITA quickly. Also, after a while I had more and more dead code, which wasn't easy to identify and I couldn't be sure that if I remove some class, I don't have any elements that depend on it. Non-deterministic resolution was also an issue for me - say user was on a page A (therefore had loaded A.css with class .main-button) where particular boxes are blue. If the user goes to page B (we load B.css which also has .main-button) he should have red boxes. But if the user gets back to page A, the boxes that are supposed to be blue are red (browser cached the style and when browser have 2 classes definitions, the one that was loaded the last "wins"). Sure, we could use IDs for everything, bundle all styles into 1 file etc., but bigger sites would have like 5MB CSS file and at the end of the day it's still hard to maintain the codebase.

I'm sure that "normal" way works for regular/medium sites (it worked for a few good years, right?), but I see ton of advantages for using the inline styles in the JS. It's not easy to "convert" to new approach, but I honestly don't look back. As I've said - it's not ideal solution, but a very important step forward.

This is a good 3-part tutorial on react, flux and some other things:

https://www.youtube.com/watch?v=Pd6Ub7Ju2RM

https://www.youtube.com/watch?v=iR22EWW-CVc

https://www.youtube.com/watch?v=6fhTawDEE9k


Thanks for your comprehensive answer, I will have a watch, read and think!

[Linking to the other discussion on this post about CSS and vjeux for future reference: https://news.ycombinator.com/item?id=9515662]


What do you think of http://www.basscss.com/ and would this kind of CSS be helpful in the situation you described?


This is the first time I saw Basscss, so take all this with a grain of salt. It seems well written, but I would put it in the same/similar category as for example Bootstrap. Basscss seems to be more modular - you can build your own "version" of Bootstrap - but Basscss gives you npm modules, so you could do something like/equivalent of require(basscss-grid). So, there are some differences that can be interpreted as a advantage of Bootstrap/Basscss, but react tries to solve the bigger problem IMO. Did you see that we're adding more and more "logic" into CSS (like animations calculations, :first, :even etc)? Where is the line? Does CSS is still "only" description of the presentation or something more? To be honest, I don't know where we are now, all those things start to merge/mix. I'd say that we're still on a quest to find the best paradigms for the web. "Regular" HTML, CSS and JS were working fine, but we're moving forward and new problems arise (how to handle different screen sizes, how can 1000 people work on the same code base, ...), so we're trying new solutions (like react and flux).

So, to answer your question: Basscss could help with some of the problems with CSS but I think that react solves problem on a higher level and does it better than any other solution we have now.


BassCSS is very different from Bootstrap or any other CSS framework. It's more like "classed inline styles", so you build your element styling like 'border border-blue blue bg-white p1 m1' (blue border, blue text on white background, 1 unit padding, 1 unit margin) e.g. you mix-and-match different CSS classes to style your elements.

So, I was thinking using React + BassCSS, and build the class string in my React components. Not sure if it makes sense, but at least it would probably be a bit more manageable and faster to develop than inline styles. Inline styles could be added on top of that of course.


If that's the case, I stand corrected. But the thing is, I still consider Basscss a solution from the "CSS world". React, IMO, takes it to the next level and combines inline styles with JS features (simple example: https://youtu.be/7YwmS0ny-58?t=58m38s - the scalable font can be done in pure CSS but I could imagine more complex use cases). Still, everybody picks the tools that are best suited for the problem and his/her preferences.

Have you checked Radium (http://projects.formidablelabs.com/radium/)? What don't you like in this approach, if I may ask?


Yep, Radium looks pretty cool for dynamic styling.


Using inline style for everything like Radium does is going to be much more expensive than using stylesheets.


That was my initial though, in CSS you can reuse classes and other code, right? But in react components can also be reused and/or extended. I would say, that using CSS makes managing big project way more expensive than using React/something similar. It's not intuitive, but you don't have to believe me, Facebook and Instagram have pretty big codebases and react with inline styles is their solution - while it's not an argument per se, it's a hint that this approach may work.


I would love to see their HoverCard and similar components open-sourced, or at least shared in a gist. Many of their abstractions sound great & generalizable.


Open sourcing a library of components would be fantastic.


Author here, happy to answer any questions or discuss further!


In the article you say you "Reuse through React instead of CSS" and that you have CSS files for the components and no global CSS classes. Do you mean that the CSS files are applied to the elements as inline styles by react, or just that each component has its own CSS so it's not really "global"?


The latter. Most of our components have an associated scss file. I didn't consider those to be global because we namespace all css rules in the style files under a class name of the same name as the component. But that's a great point, it didn't occur to me that that paragraph may have only made sense to people familiar with our conventions.


Interesting. Asking out of curiosity, not skepticism: why not use react styles in js directly, à la vjeux et al?

Reasons I'd guess: not being able to use pseudo-selectors and things like :hover; familiarity for designers; easier use of legacy code; benefits of SCSS that would take work to re-implement in js. But I'm curious what your real reasons were!


That's pretty much it! Although the ideas presented here do make sense (https://speakerdeck.com/vjeux/react-css-in-js) we haven't gotten there yet. Our css namespacing scheme solves the "global namespace" issue, which was the biggest issue that stood out for us.


I like the vjeux thing, I think for dynamic sites if we replace static html and css with javascript the world will be a better place.


Hi, how does React work with other libraries that modify DOM state arbitrarily? How might d3 dom changes or canvas context calls work with React


Nice, we're actually posting a tutorial in a week or two about how we use d3 + react. I'll try to summarize though.

In the case that a library modifies the DOM, we try to keep React out of it's way. React works best when it has full control of the DOM. In these cases, React components are more of "wrappers" for the 3rd party libraries. Mostly by using the componentDidMount/componentWillUnmount to initialize/destroy the third party library, respectively. And props as a way of giving the parent a way of customizing the behavior of the third party library that the child wraps.


We use Google ads in our React apps, and it turns out to be a problem. I wonder if anyone has solved it in a satisfactory way.

Basically, with GPT you have named slots identified by their DOM element IDs. You can "refresh" a slot any time, which will populate the element if it's empty, or load a different ad.

So we do that when we're mounted. Unfortunately, if the page structure changes, React will re-render the component and blow away the contents -- anything GPT has put in the element is considered alien.

That's fine, we just refresh. The problem is knowing _when_ a render has finished and the ad element is empty. In my testing, React elements would often have a delay after which their changes have been applied to the DOM; so I use setInterval to check repeatedly for an empty element. It seems like a stupid solution, but I couldn't figure out a more solid way; there's no React callback for completed renders.


Seems to me you could wrap ad elements in container components that have:

shouldComponentUpdate() { return false; }

Which would prevent React from re-rendering them after initial mount... any reason why this doesn't work? I do this often when using d3 selections to keep React out of the way and catch incoming props in componentWillReceiveProps instead.


This is the right answer. This will effectively keep React from touching the element ever again after the initial render.


I'm intrigued as to why you think this approach is better than using a key? The 'shouldComponentUpdate' way of doing things means any changes to props or state on the component have to be handled manually, which can introduce a lot of non-trivial and overly complex code.


Do you have the 'key' prop specified on these components? React uses the key to keep track of a particular element. If you specify your own unique key, react will know that the dom representation of a component matches your react instance, and thus not replace the dom element when changes happen in a parent component (apart from if the component or parents are completely unmounted).

Without the implicitly set key, react creates its own index, so if a change happens in the hierarchy above your component, a new key might be given by react, causing the dom element to potentially be replaced when rendering.


Never used Google Ads, but you should be able to do something like

  var GoogleAd = React.createClass({
    getInitialState: function() {
      return {
        id: makeUniqueId()
      };
    },
    render: function() {
      // Since this is always the same, React won't try to change the contents
      return <div id={this.state.id} />;
    },
    componentDidMount: function() {
      googletag.defineSlot('/1234567/sports', [728, 90], this.state.id);
    },
    componentWillUnmount: function() {
      // Clean up the slot and any other resources here
    }
  });
and then not worry about it.


It would probably be good to supply a `key` property to the div to ensure that React never tries to reuse it (say, when changing from one GoogleAd to another).


Can you somehow use store to... store the ads? Like use getInitialState() to load the ads and use render() to just display it. I feel that you want to use regular MVC, while in React you should think of one-directional data flow (flux architecture). I probably don't understand the problem here, maybe if you would provide more details/some code I/somebody could help.



Got a FOUC (especially on the webfonts) the first couple of renders on the page; looks like the overloading of the META tags might be to blame.

Otherwise, really good stuff here as someone rapidly picking up on React.


Were you looking at the siftscience.com marketing site or the Sift Science console?


I noticed in your first code example you use a mixture of leading a method with an _ and some without. Ex. navigateToContact vs _hasUnsavedChanges and _saveChanges. I read somewhere that a best practice is to always prefix custom methods with _ to differentiate from React core methods. What're your feelings on that?


Oh this is definitely a personal preference thing, but our convention is this: private instance methods start with an underscore, public instance methods have no underscore. Public ones have no syntactic difference from the core life cycle methods but that's ok to me because they're all easy to remember. Btw we use public instance methods very sparingly, basically as a last resort when all else fails.


Awesome. Thanks again for the write up. I love reading well written Javascript.


Great article, thanks for sharing! Would have loved a few code samples to go along but your descriptions did an impressive job describing what's going on.

One question: what does that "global Backbone cache" look like?


Thanks! Glad to hear it was easy to follow and didn't ramble. Our backbone model cache is a simple module that you request backbone model instances from by a unique key. You also pass initialization options in case it doesn't exist in the cache. The instance will be constructed, saved in the cache, and returned. You can pass a TTL also. It's not great, feels clunky, but it works.


React is supported by a ton of goodwill from a lot of camps. What you offer here seems like some particular experiences you had. To say it's a best practice because it explains your world feels to me laden with folly. Linking a particularly wishy-washy state v.s. props article in core docs as if it's the final gospel- reeks of finding easy convenient idols to call out that make you sound better- it sells your article with a notion of completeness, declares a kind of finality. Nearly every point raised comes to me more as a question, a thing we have some rough anecdotes to tell, rather than something actually informative or much less definitive. I'll just start walking down your article's core bullet points.

Use componentShouldUpdate well: yes, do. You'll know why you should, quickly enough.

State v.s. props is a great point, but then you need both declarative managed injection via props to initialize or control, mixed with a transient stateful interactivity when the user begins free interactions. Early experiments in "best practices" are efforts like React-Controllables, trying to create components which are isomorphic to state v.s. props driving them.

Everyone is doing their own experiments with how and where data lives and how and where it gets there. That's the nature of webdev, experimenting with pipes. Some cursory words on Flux in your article indicate how vastly unresolved and mysterious the ???->data part of the webapp equation is. "We're experimenting with something Relay like". So way Soundcloud in 2012. Best practice: use react for the next step, data->html.

Best practice: wrap the most boring boilerplate css with your own react components. Oh great, just what everyone needs to go do. Recommendation is to not rely a lot on css, but how, if not global, do we start sharing some style rules effectively? It's disingenuous to offer this as settled "be balanced" best practice, particularly when it's still the hay days of excitement, with new encompassing visions like https://github.com/petehunt/jsxstyle/ just popping up.


It looks like you're bucketing the ideas in the post into one of two categories. Either 1. Too obvious to write about or 2. Not a best practice because new ideas are always being introduced.

Regarding the first, those topics weren't obvious to everyone. Besides no one really benefits when posts are called out for this.

And re the second, these patterns have emerged from one year of maintaining a large app with a growing team. The points mentioned are tips for writing code so that your app will scale, not silver bullets for complex topics such as the general question how to write styles for React. The best practices mentioned in the post are just that, but they're not the only ones.


I've been looking at reactive UI design, and it seems weird to me that React.js has this React.createClass and .setState stuff. It seems like it would be better to let the user manage the state and just re-render whenever the state changes. Am I missing something about how this works that makes those necessary?


You can choose not to use the React component abstraction at all and just re-call React.render(makeElements(state), el) at the top level each time your app changes (using pure functions to generate the tree). Our plan is also to support pure functions directly for components that don't rely on state.

You can also use the component abstraction but choose not to use getInitialState/setState -- but our goals are to provide a component abstraction that is flexible enough to meet people's needs while still being restrictive enough for us to build higher-level optimizations around them.


By making it explicit and a bit clunky, you discourage users from using state.

Without explicit functions to be called, you can't detect state changes and would need polling. This is terrible.

At the end of the day, it's a limitation of JavaScript because unlike with Python, for example, you can't have automagic getter/setter functions. They have to be called as functions.


Actually, custom getters and setters exist in ES5:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guid...

AmpersandJS, for example, implements its observable pattern in this way:

http://ampersandjs.com/learn/state

That said, I don't think the pubsub/rx/observables pattern is the most optimal for UI development, since it still allows for cascading event chains. Modeling all application state as a large data structure that allows for efficient diffing — which nicely mirrors the diffing react does with both it's internal component tree and diffing with the DOM — is a much more straightforward approach. Just re-render your application 60 times a second, like a game engine, and make that process as efficient as possible.


This is exactly where I am hoping reactive ui ends up. If you don't want to do 60 times a second you can render only on certain events like network call or mouseover. If you do the rendering in requestAnimationFrame you can batch things easily.


Seems like .observe() would fix that polling thing, right?

http://www.html5rocks.com/en/tutorials/es7/observe/

Also you could just re-render whenever any event happens, which is probably when your state changes anyway.


Observe just makes making bad apis easier imo. I don't care if react can detect state changes, I want to detect state changes by searching for setState.


It would if browsers supported it: http://caniuse.com/#search=observe

So far exists only on Chrome and Android browsers.


One reason for the explicit method may be that React does an internal optimization where it batches state updates together. Two calls to setState can result in just one render.

https://groups.google.com/forum/#!msg/reactjs/R61kPjs-yXE/ys...


No reason why this wouldn't be possible with Observe, the first call schedules a re-render and the next one doesn't do anything since there's already a re-render scheduled.


A possible issue is setState doesn't transition the object's state, it creates an async future/pending state transition (and multiple state transitions can be batched). Object.observe can only operate reactively, the state has already changed and the next dereferencing of state data will see the "next state" instead of the "current state".


I believe `React.createClass` will be deprecated in the future in favor of ES6 classes.

As another commenter mentioned, explicit `.setState` makes it much easier to see where in your code you're triggering changes. It also helps you think, "okay, I am mutating the state here... is that really what I want to do?"


You are absolutely correct; this is what Mithril.js does. In Mithril, a component is a plain JavaScript object with only two properties: controller and view. No set / replaceState, no component[Will | Did][Mount | ReceiveProps] – just plain JavaScript data structures.

Because Mithril uses plain JavaScript constructs, you can use standard design patterns and techniques when constructing and managing your components. Everything works beautifully.


Why isn't the Mithril library more popular?


It's getting more and more popular every day! It just doesn't have a billion dollar company's marketing budget to promote itself :)


I've wrtitten a book to show how to integrate Rails with React.js. It uses Backbone to act as Router. You can try it at https://www.gitbook.com/book/checkraiser/rails-and-react-js/...


Suggestion: do not change any ui in any event handlers, otherwise you are doing it wrong




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: