I normally suggest eschewing the javascript class model in favor of using stateless functional components.[0] I've found them simpler to understand and it cuts down on unnecessary typing. I almost never use 'this' in javascript, and instead have favored an OLOO[1] or pure functional style as it fits into a simpler mental model for how things are working.
I normally only test the actions that modify state in my javascript applications. I care that I'm correctly changing the state of my application, not what that state renders. (This is similar to rails apps not typically testing html output) I normally use mocha[2] for testing and if something goes wrong I can open up a normal chrome js debugger using the --inspect-brk flag when running via the cli.
You will eventually find yourself needing to support multiple routes in your react applications. Most people would recommend the "react-router" library, but I've found a lot more success with "redux-little-router"[3]
[0]: https://reactjs.org/docs/components-and-props.html
[1]: https://github.com/getify/You-Dont-Know-JS/blob/master/this%...
[2]: https://mochajs.org/
So I do this whenever possible, but the way this advice is worded (both here and often in the wild) makes it sound like you can just use them everywhere.
Most UIs have state. I can't imagine a UI that doesn't. Every third component or so I write I end up using classes for, so I've got a mix of classes and functional components throughout the codebase. Do you _never_ use classes? If so, what do you do instead? Otherwise if you're like me, you get to use functional components occasionally which is nice, but are nowhere near being able to get rid of the class syntax.
import React from "react";
import { connect } from "react-redux";
function _HelloWorld({name}) {
return <div className="intro">{name}</div>
}
function mapState(state, ownProps) {
return {
name: state.name
}
}
function mapDispatch(dispatch, ownProps) {
return {}
}
export const HelloWorld = connect(mapState, mapDispatch)(_HelloWorld)- Only add the `ownProps` argument to `mapState` or `mapDispatch` if you actually need it, because `connect()` will now call those functions more often (whenever the incoming props have changed). If you're not actually _using_ values from `ownProps` in there, don't add those arguments.
- The `mapDispatch` function isn't doing anything at all in that example, and can be omitted completely
- I personally recommend using the "object shorthand" form of `mapDispatch` instead. To me, there's never actually a good reason to write a separate `mapDispatch` function. Just write action creators, and pass them in an object to `connect`, like this:
import {addTodo, toggleTodo} from "./todoActions";
const actionCreators = {addTodo, toggleTodo};
export default connect(mapState, actionCreators)(TodoList);Snapshot testing probably makes sense if you're making a design system of component building blocks or a purpose-built re-usable component. Anything more and your tests will probably end up being brittle.
For routing, I usually recommend "connected-react-router." [1] Never heard of "redux-little-router" - will have to check it out!
Redux on the other hand was a little more confusing for me to learn (the concept makes complete sense, it's the implementation and debugging that gets confusing). The great thing about Redux is that you don't have to use it or learn it. The React ecosystem is pretty well decoupled so you can choose how you want to manage state and async tasks. That is it's biggest selling point for me personally.
My experience with front-end frameworks started with Backbone + a ton of jQuery to AngularJS to React (with many different state management libraries). I found that Backbone didn't really provide much on top of jQuery + lodash/underscore, but I liked that it didn't make too many decisions for you. Angular (v1) on the other hand, forces you into some unconventional patterns (ie: the whole service vs factory fiasco and it's own dependency management system). It's fine if you aren't using a separate dependency management library (or ESM), but if you are, you have to declare dependencies twice. Angular 2/4/5/whatever-arbitrary-number-they-are-on-now has been way more confusing for me to learn as they make you learn their own templating language for things like loops, control flow, etc and still have some weird patterns around dependency injection. JSX is a lot simpler if you know basic JS. React seems to have the least amount of boilerplate code as well especially if you make use of functional components.
But what happens when you inevitably need to step outside the boundaries set by create-react-app? From that perspective, it simply delays the problem, rather than solving it.
For me personally it would be exasperating to learn all of the stuff that CRA bootstraps before actually getting to learn React.
I had a gulp build process I used before create-react-app; it was gross to get working, but then worked just fine. I could live without create-react-app, but why would I?
Been working on a real-world c-r-a based project for 8 months and this is yet to happen. And the upgrade process has been a dream (update 1 dependency), no breakages so far.
In fact I now regret my other attempts to go off the rails (adding Sass), it wasn't worth it.
A lot of the time, simply using react-app-rewired is sufficient in place of ejecting, especially if the only thing you need are some Webpack plugins.
At my company, we use cucumberjs (https://github.com/cucumber/cucumber-js) to write scenarios for basic front-end testing. I wouldn't go overboard and start writing test to measure padding or font sizes, but you can easily see isolated scenarios and write automated tests to simply verify that a react component actually put the right element in the dom or to check conditional class names.
We also unit test many of our Redux reducers which is pretty simple with any unit testing library. Just create an initial state and expected state, call the action creator, and deep compare the new state with the expected state.
What I do wonder about is inline styling in JSX that I encounter so much in React code.
It feels "wrong" to me as inline styling has been considered a "bad" thing forever.
Among React pros is inline styling not considered a code smell?
Shouldn't style live nicely in CSS files?
But I just want to say, as an alternate data point, my experience has been exactly the opposite. I love React. React is the first front-end technology I have ever managed to get to stick.
* ES6 is just a detail, I know. But for me, ES6 transforms Javascript from an idiosyncratic scripting language where I constantly have to look up the ordinary way to handle basic programming tasks into something resembling a modern high-level language. To me, ES6 turns Javascript into Ruby. I don't love programming in Ruby, but I can do it quickly and without the language getting in my way.
* The basic idea behind React, that your UI rendering code is always working with a snapshot of the current state, and 95% of your job is just to take that state and re-render it wholesale, eliminates a huge amount of the cognitive load I experience trying to do front-end stuff. I allows me to stop thinking in state machines, and just write straight-line code. If you've been primarily a backend person and have always sort of hated doing front-end stuff, check out React and see whether it's just the programming model that's been bugging you.
* Unlike the author, I've always been more of a programming person than an HTML/CSS person; I would kind of rather eat a bug than fiddle with CSS. One thing that makes React so nice for me is that you can just buy an HTML template and gradually turn it into JSX to "animate" it into a UI. Another thing is that it so nicely decomposes into components that there are a bunch of high-quality UI component libraries to draw from.
I have a lot of the same problems with React that everyone else does:
* "This" and the JS class model still feel like own-goals and I'm regularly tripping over them. But I'm never stumped by them; the bugs are always pretty obvious and easily fixed.
* Perf has been an issue, particularly memory consumption. But to me, this just suggests that I'm actually productive in React, that I'm getting to the point where I'm comfortable enough belting out code that I'm generating perf problems to go fix. (This has come up on relatively complicated UI projects, like the debugger interface we did at Starfighter, which was a monstrosity).
* The tooling was a disaster before create-react-app. But now there's create-react-app, so the tooling isn't a problem.
* I still have no idea what the right way to test things is.
I'm not rebutting the article at all! Different people, different issues. I just thought, if that perspective was valuable, mine might be too.