Bootstrap and the Active LI Issue

Installing Bootstrap and Font Awesome was trivial in both cases. This is a very standard Webpack setup, and has no problem with well established tools.

It was the Active LI that quickly turned into an abysmal clusterfuck. Just to recap, Bootstrap wants its “active” class on the li, rather than the actual a tag, something that isn’t the default for frameworks. Getting access to the current route in a link wasn’t particularly intuitive. In theory the NavLink component should do it, but because the element we want to modify isn’t the link itself that wasn’t possible. Using Bootstrap, I found I needed to install React Router Bootstrap and React Bootstrap. And that added a new component of LinkContainer . For some reason I had a weird issue with this, meaning it was always considering the index page as “active” for whatever reason. I tried a lot to fix this, including using Switch and making sure my home path was set to exact. In the end it turned out I needed a separate component again, an IndexLinkContainer . Debugging and fixing this sort of nonsense is time consuming and frustrating. When React people tell you how easy React is, they tend to skip over this kind of bullshit. Thanks to installing React Router Dom, React Router Bootstrap, and React Bootstrap I ended up with this.

<Navbar>

<Nav>

< IndexLinkContainer exact path="/">Home</ IndexLinkContainer >

<LinkContainer path="/todos">Todo List</LinkContainer>

<LinkContainer path="/about">About Us</LinkContainer>

</Nav>

</Navbar>

That all looks fine, but for some strange reason, that markup when implemented puts a spare container element inside the first navbar. This leads to a bit of annoying margin on the left hand side of the home link. Why the hell that’s in there I’m not sure.

edit: I looked into the above more, and it turns out Bootstrap best-practise is to put a container inside a nav where the parent container is not fluid. I’m not sure why, but I’m not going to criticise React Bootstrap for being right.

List Item Components

Obviously we want to do more than just loop and show the titles, so we need to have a component to isolate those behaviours. This is where things get a bit strange in React. Not all components are equal, and terms come flying at you quickly.

A component can be a smart component, a layout component, a render callback component, a conditional component, a functional component, a presentational component, a higher order component, a controlled component, a container, a class-based component, a stateless component, or a child component.

And I only made up one of those. Maybe two.

A functional component is a simpler form of component, which is suitable for basic components that just need a render function, with little or no behaviour. They’re also not capable of having a state, and need their state passed in as a prop. They would be an ideal use for the application I was making, so of course I didn’t know I was supposed to use them and did everything wrong.

I built a component with a lot of assumptions, based largely on the components I built for previous frameworks. In retrospect I would do it differently, breaking down into smaller stateless functional components, which is apparently more idiomatic for React. In truth this is probably good advice for any modern framework. Smaller, more focused components with less or no state.

My larger component went fine, though. The content of an li tag modified by the presence of a state isEditing variable, then buttons that set internal state, etc.

Updating and Creating

Rob Eisenberg, the developer of Aurelia and Durandal, said something in a presentation a while ago that I’m reminded of now.

React is much better for read only apps. It’s more difficult for input intensive apps. — Rob Eisenberg

Editing with React is odd. There’s a particular pattern that occurs, where the value of an input needs to be reactive. This is called a “controlled component” in React parlance. React disapproves of two way binding — I’m not sure if it is even possible. The approach instead is that the value of an input is set from state. Changes to the input update the state, but state changes trigger a re-render. Which would wipe the value that was just set.

This means that every input being changed needs an explicit handling method (though admittedly it’s usually achievable as an inline setState call) and a property defined in the state. That’s a lot of boilerplate for something other frameworks handle without the bullshit. It’s also a very circular and oddly inelegant pattern which is not at all intuitive, and quite error-prone. It’s easy to end up with broken fields as typing redraws out your changes.

Inelegant or not I ended up with a solution but it involved some obvious downsides.

Updating state was successfully achieved, but that was only local component state. One way binding means the actual state of that object is now ambiguous. The item component is in one state, the list component is unchanged.

You need one of two approaches to manage state: two-way binding, or a central store. Angular chooses two way binding. So does Aurelia. Ember does both, two-way binding to the store. React does neither. This leaves the user in charge of all state maintaining. This is something I expected would be easy in such a simple app. I was going to be smug and point out that see, you probably don’t need Redux.

And to a degree I was right.

The correct solution here would be “lifting scope”. Rather than having a “smart” TodoList component and a smart TodoItem component with its own internal state, I could have a dumb and simple TodoItem. All the state managed by the TodoList and then passed into the item.

In principle the item component could then be a “stateless functional component”, a much simpler structure that eliminates local state for a corresponding increase in clarity and performance. In practise I didn’t bother — though I didn’t need the local scope I did want to keep the helper functions I was using for the interface elements. Ideally those helper jsx functions could themselves be stateless functional components, but that was a step I didn’t bother going down.

The above was the correct solution. I have to stress that for an application of this size the above was absolutely all that would be necessary, and all that would be preferred.

But the intent of this investigation wasn’t to find out how to make a ToDo app in each framework, that’s trivial. It was to implement it like a real production app. In order to be honest and useful it would need to implement this app as if it was a bigger and more complex app, dealing with a lot more concerns. It really needed to use Redux.

I have to say again that Redux is not always necessary and is far too often reached for when React’s internal setState makes much more sense. I have used it here in full knowledge that it was a needless complexity.

Refactoring to Redux

Devotees will tell you that Redux is a simple pattern, that it just uses a few basic elements so it can’t be complex. But that’s misleading — human DNA is made of only four nucleobases and we’re pretty complex.

In truth I found Redux to be the single most frustrating and complex thing in this entire project. While Redux itself is (arguably) a simple enough pattern, the process of binding a React app to the Redux pattern is a complex one. I watched numerous video series and eventually signed up for a paid course on Udemy, just trying to learn this shit. No other framework required professional tuition.

People telling me this is simple and dismissing it can go fuck themselves. Redux is simple…. once you understand it. But gaining that understanding is not a trivial thing, and it’s frustrating and insulting to have that challenge hand-waved. I’m speaking only from my own experiences, here. Maybe it’s easy for others, maybe I’m unusually thick, I don’t know.

It’s OK that it’s complex. Some things are complex. Some things take learning. But it’s better to acknowledge and accept that than pretend it’s not the case and treat new users like they must be some kind of moron to struggle. Again, it’s not so much Redux as React-Redux. Acting like Redux lives in a vacuum is misleading.

In any case, the core problem with implementing Redux in something like isn’t just that it’s complex. It’s that it’s irreducibly complex. With most complex systems or patterns you can muddle through it. You might have it a bit wrong, or be missing part of it, or dodgy up some elements. But with Redux in React you really need to have a complete and comprehensive understanding of the entire pattern, and have it perfectly implemented in order to get anything working at all.

Using Redux leaves the user with lines like this.

export default connect(mapStateToProps, mapActionsToProps)(TodoList);

This is a standard bit of Reactdux code that will be familiar and unremarkable to anyone who’s used the pattern, and completely arse to anyone who hasn’t.

The use of Redux adds a staggering amount of boilerplate to a React application. Every component with store access needs a function to connect state into the props, and then another one to connect actions in the same way.

function mapDispatchToProps(dispatch){

return bindActionCreators({fetchItems, createItem}, dispatch);

} function mapStateToProps(state){

return {

todos: state.todos,

currentItem: state.currentItem

}

} export default connect(mapStateToProps, mapDispatchToProps)(TodoList);

Roughly that (give or take) is required on every single component with access to the Redux store. React components with Redux are considered “containers”. And so this means a component can be a functional component, class component, container, or controlled component. Probably a bunch of other terms people throw out wildly and you have to look up.

The store itself has to be created and injected into the app as well, meaning a shitload more boilerplate for setting up the store and middleware in the index, though at least it’s confined to one place.

That is going to seem universally critical, and to some degree it is. There are things I like about Redux. Most particularly I like it as an organisational pattern. Events can all be managed in one place, as can the effects they have. HTTP requests, for example, can be put in the actions. The monolith frameworks all have a service injection pattern or in Ember’s case, a larger abstraction over data access. The library based frameworks, React and Vue, can end up with things like api calls scattered through various lifecycle hooks. This is one of the things I like least about the solution I ended up with for Vue. There’s no cohesive, correct place to put things like this. Flexibility is seen by many as a benefit, but there are benefits to something being guided and structured, especially if there are well built escape hatches.

The thing about Redux is… it’s hard to put this in a way that isn’t going to make React developers really mad. But I don’t see the big deal. There’s nothing Redux does that Angular’s Observables doesn’t do with more functionality and less boilerplate.

If you just want a store, Ember has one built in out of the box and it’s tied beautifully in with the rest of the framework. Vuex similarly manages state with vastly less boilerplate, though it’s really just a store, lacking any structural advantage.

Don’t get me wrong, I see the benefit of Redux. But it really is a lot of boilerplate and complexity. In truth, Redux feels like a base pattern that the framework I want to use would abstract for me. That is, after all, the point of frameworks.

I’m not alone in thinking this, and there are abstractions for Redux such as Kea. Kea takes away a lot of the gibberish binding code by using decorators. I’m not convinced it’s really an abstraction, and may just end up moving all of the code into the decorators instead.

React Tunnel Vision

One thing I do want to call out before I finish. In doing this article I researched extensively what benefits frameworks have over alternatives. For React more than any other, its advantages are — to be frank — complete bullshit.

For example, a React presentation made literally a week before writing the React section highlighted “Virtual DOM” as a key benefit of React. But V-DOM diffing is the pattern used by all of these frameworks, with the exception of Aurelia. It’s hardly a point of difference.

Here’s a fine example: https://www.altexsoft.com/blog/engineering/the-good-and-the-bad-of-reactjs-and-react-native/

Every benefit listed here is common to every other framework with the exception of v-dom mentioned earlier. If these are reasons to use React, and they’re not valid, does that mean there’s no longer a reason to use React? Ironically, every con here is unique to React.

I’d recommend React supporters look seriously at some frameworks like Angular or Ember. There are some great ideas, and the developer experience may well be a breath of fresh air. This isn’t to say that you should abandon React, but it might be worth knowing what’s happening across the fence. Having multiple tools in your box can always be beneficial.

Conclusion

I’m glad I came to grips with React. To be completely honest it’s one I’ll definitely continue with. Not because I love it, but because React dominates the frontend space in certain areas, such as remote work and startups.

React developers more than anything remind me of people who insist that you have to build your own PC from parts. That way you get complete control over every aspect of the final product. But I did my time doing that shit. I did my time sourcing optimal parts and putting them together. I’ve cut the crap out of knuckles and stabbed myself with screwdrivers. (I didn’t say I was good at it.) These days I just go to an Apple Store and buy a laptop. I’ve got things to do and I want a tool that helps me do it.

Ultimately it comes down to abstractions. I’m a fan. I like a good abstraction. I think they’re useful and important. There’s no right answer here, I’m speaking from my own perspective and preference. And to me, the boilerplate-heavy and error-prone nature of a React application is a concern. The need to learn and understand a range of solutions from Redux to Thunk to Saga, etc, means these things fly thick and fast.

Where my analogy about building a PC falls apart is that building a PC actually does make for a better product in the end. React devotees will make the same claim. I’m not convinced by it.

But more than any other framework I know I’m just scratching the surface with React. There’s a lot to learn. I hope it gets easier.

Github Link