DEV Community

Valeria
Valeria

Posted on • Originally published at valeriavg.dev

Me & React: 5 years in 15 minutes

I first heard of React when a friend showed me a project he had written. It was some sort of content management system: it had tables, forms, visual editors and stuff like this. I don't remember much, except that code was really really confusing, it looked like this:

// hint: you can use this codepen to follow along:
// https://codepen.io/valeriavg-the-flexboxer/pen/WNJNMRp

const app = React.createElement(
  // tag
  'button',
  // properties
  {
    onClick:function(){alert("Hello!")}
  },
  // children
  "Click Me!"
)

ReactDOM.render(app,document.getElementById('app'))
// <div id="app"></div>
Enter fullscreen mode Exit fullscreen mode

So, of course, I was quite frustrated someone would want to write that, when you could just write this instead:

<button onClick="alert('Hello!')">Click me!</button>
Enter fullscreen mode Exit fullscreen mode

JSX: HTML in JS

Some time passed, and, to my surprise, React was all over the place: every other job advertisement was mentioning it.

And so I gave it another try. This time around it wasn't just a library you import - somehow it turned into a whole new language, called jsx. Which, however, was vaguely familiar:

const app = 
     <button onClick={()=>alert('Hello, JSX!')}> 
      Click me! 
     </button>

ReactDOM.render(app,document.getElementById('app'))
Enter fullscreen mode Exit fullscreen mode

That was almost the same as my old pal HTML, except JSX allowed splitting HTML pages into tiny reusable dynamic building blocks:

const One = () => <div> One </div>;
const Two = () => <div> Two </div>;
const Three = () => <div> Three </div>;
const app = (
  <div>
    <One />
    <Two />
    <Three />
  </div>
);

ReactDOM.render(app, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

Behind the scenes, however, it was still the same code:

const One = () => React.createElement('div',{},'One');
const Two = () => React.createElement('div',{},'Two');
const Three = () => React.createElement('div',{},'Three');
const app = React.createElement('div',{},One(),Two(),Three());
ReactDOM.render(app,document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

But JSX made a lot of difference and React has finally started making sense to me.

Stateful and stateless components

One of the first things I've learned was a "stateful" component:

class App extends React.Component {
  constructor() {
    super()
    this.state = {
      name: ''
    }
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name} </h1>
        <input
          type="text"
          value={this.state.name}
          onChange={(e) => this.setState({name: e.target.value})}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

Or rather it was the second thing, as, apparently, I've already got familiar with it's "stateless" counterpart.

A stateful component had a state which was triggering a re-render on change, while the stateless had only the render part and were rendering exactly the same thing as long as props were the same:

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}! </h1>
      </div>
    );
  }
}

ReactDOM.render(<App name="React"/>, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

Back then I worked for a startup which allowed creators distribute video content for their fans among other things. That meant we had a dashboard for creators, and website and an app for end users. And React worked perfectly well for the dashboard, especially when functional components came along:

const App = () => {
  const [name, setName] = React.useState("");
  return (
    <div>
      <h1>Hello, {name} </h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

And so, the project was growing, along with the amount of dependencies. We used emotion styled components, react-router and of a little something to manage the state.

State management

One of the first libraries for state management I've tried was RxJS. Sure, it added even more magic to the project, but hey, it was cool to share state between two components, right?

Wrong, it was chaos! I could never tell which one of them changed the state and it made debugging quite mind bending, as sometimes console.log has been printed a microsecond before the state has been actually propagated.

Redux has treated me a bit better in that sense, but having one gigantic store was not convenient for my preferred modular architecture.

And so I stuck to the React's own context because I could easily split states and trace the updates easier:

const NameContext = React.createContext("");

const Name = () => {
  const name = React.useContext(NameContext);
  if (!name) return "";
  return <h1> Hello, {name}!</h1>;
};

const App = () => {
  const [name, setName] = React.useState("");

  return (
    <NameContext.Provider value={name}>
      <div>
        <input
          value={name}
          onChange={(e) => setName(e.target.value)}
          placeholder="What's your name?"
        />
        <Name />
      </div>
    </NameContext.Provider>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

Which, as you can tell from the code, was precisely around the time functional components came along.

Functional components

In a nutshell, functional components were an attempt to turn stateful components into stateless with ease and vice versa by letting them all be functions and use hooks instead:

const App = () => {
  const [name, setName] = React.useState("");
  return (
    <div>
      <h1>Hello, {name} </h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

I can't argue that code became much easier to write and read, though I had my concerns regarding hooks. First off, the state still needs to be stored somewhere and originally it was proposed to be built around this, which wouldn't work with arrow functions and would need to rely on the fact that JSX is compiled (not the case as at the moment it uses a dispatcher instead). And secondly, it required thinking in React.

While classes were a mouthful - they were straightforward - there were explicit props and state, and when state or the props would change - the render method would be triggered. And there were a couple of methods you could use to control this flow, like shouldComponentUpdate or componentDidMount:

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      name: ""
    };
  }

  componentDidMount() {
    console.log("Component did mount!");
  }

  shouldComponentUpdate(props, state) {
    console.log({
      new: { props, state },
      old: { props: this.props, state: this.state }
    });
    return true;
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.state.name} </h1>
        <input
          type="text"
          value={this.state.name}
          onChange={(e) => this.setState({ name: e.target.value })}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

Which when turned into a succinct functional component with hooks looked liked magic:

const App = () => {
  const [name, setName] = React.useState("");
  React.useEffect(() => {
    console.log("Mounted!");
  }, []);
  React.useEffect(() => {
    console.log("Name changed:", name);
  }, [name]);
  return (
    <div>
      <h1>Hello, {name} </h1>
      <input
        type="text"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

I can't say I know every aspect of how it works now, years after, and back when it was some wild juju I gave up trying to comprehend. Unfortunately, things I don't understand have a tendency to bite me when I least expect it.

Handling performance issues

As I mentioned, React was a working great for our dashboard, and so I've decided to switch our plain old MVC website to a fancy server-side rendered React. That was before NextJS became the de-facto standard for this and I've kinda just glued most pieces together myself: after all, it boiled down to replacing the template engine we were using (I think it was pug) with ReactDOMServer:

// 
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const script = React.createElement('script',{},'console.log("ReactDOM hydrate would happen here")')
const page = React.createElement('h1',{},'Hello, SSR!');
const app = React.createElement('body',{},page, script);
ReactDOMServer.renderToString(app);
Enter fullscreen mode Exit fullscreen mode

The new version was quite ok and I could add some real reactivity to the otherwise static pages, including the changes to a video player.

I learned that some things required dropping down plain old JS event listeners with the use of refs:

const App = () => {
  const videoEl = React.useRef(null);
  const [time, setTime] = React.useState(0);

  const onTimeUpdate = (e) => {
    setTime(e.target.currentTime);
  };
  React.useEffect(() => {
    if (!videoEl.current) return;
    videoEl.current.addEventListener("timeupdate", onTimeUpdate);

    return () => {
      if (!videoEl.current) return;
      videoEl.current.removeEventListener("timeupdate", onTimeUpdate);
    };
  }, [videoEl]);

  return (
    <div>
      <p>{time}s</p>
      <video
        ref={videoEl}
        src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
        controls
      />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
Enter fullscreen mode Exit fullscreen mode

But, as I discovered after, rendering anything on the screen is an expensive task, let alone a high abstraction like HTML/CSS. Now imagine fetching a video stream, processing it, playing and rendering UI changes every frame with the help of a virtual DOM diffing:

Laptop on fire

Yup, that's what was happening. Now of course, React was not the main issue - the video processing and playing were the heavy ones, but there were so little resources available and so many optimisation required to make it work properly with React, that I gave up and wrote the player interface is plain JavaScript and just "mounted" it on the React component:

const App = () => {
  const videoEl = React.useRef(null);

  React.useEffect(() => {
    if (!videoEl.current) return;
    mountVideo(videoEl.current);
    return () => unmountVideo(videoEl.current);
  }, []);

  return (
    <div>
      <div ref={videoEl} />
    </div>
  );
};

const mountVideo = (el) => {
  el.innerHTML = `<div class='time'>0s</div><video src="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" controls/>`;

  el.querySelector("video").ontimeupdate = (e) => {
    el.querySelector(".time").innerText = `${e.target.currentTime}s`;
  };
};

const unmountVideo = (el) => {
  el.innerHTML = "";
};

ReactDOM.render(<App />, document.getElementById("app"));

Enter fullscreen mode Exit fullscreen mode

After this I've build several quick prototypes with the help of GraphQL and React Native and worked on yet another dashboard in React / Redux.

I think by then I finally learned to think in React, but nonetheless from time to time I still turn useEffect into an endless cycle of updates and forget to memoize stuff.

But I didn't want any of it: I didn't want to learn a language within language with a dozen of libraries, I didn't want to change the way I think - I just wanted to make a performant web application as easy as possible. And I couldn't help but resent React for it.

Yet today I came across a really interesting project, called atomico - a WebComponents library, inspired by React hooks; And it dawned upon me that without React, and, particularly JSX - none of it would be possible, not my beloved svelte, not flutter, nor dozens of other frameworks.

And just as I'd advise any web developer to learn basics of so-called "vanilla" JavaScript, I highly recommend to look into a library that shaped the modern web technologies, at least out of curiosity.

Hopefully, it'd take you much less time to master than it took me :-)

Top comments (42)

Collapse
 
abbasc52 profile image
Abbas Cyclewala

React did have a major influence on many modern day frameworks. But i do feel many frameworks over complicate simple process and rename it. For e.g. Using a function to generate stateless component...is same as having a function which renders html/template 🙆‍♂️. It is better to learn vanilla rather than a rebranded version of vanilla feature.

Collapse
 
valeriavg profile image
Valeria

I agree, knowing underlying technology is never a bad idea!

Collapse
 
abi0l9 profile image
Monsur Oyedeji

A reason why it would be hard for newbies to just bump in to learning React without knowing the language which inspired it.

Collapse
 
abbasc52 profile image
Abbas Cyclewala

The real problem is people learn React(or any other framework), which gradually changes its ways every few years... Later you need to relearn things... All of this because a single entity dictates the way a framework works.... If only most frameworks could lean into vanilla features, their knowledge would be relevant for years to come

Collapse
 
luiz0x29a profile image
Real AI

I'm still baffled we don't have a component library and DOM diffing being done by shadow DOM on native code in the browser.

Come on, this is 2022.

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

Thanks for sharing! It was a great read.
Been working with React for some time now and I wouldn't enjoy it as much if I had to work with class components. Functional components actually make sense for me and I think is 100x easier for new people coming to the library. Even for die hard Java programers and their sea of classes.

Collapse
 
valeriavg profile image
Valeria

Thank you!
Yes, it's definitely easier, at least till the first endless cycle 😁

Collapse
 
raibtoffoletto profile image
Raí B. Toffoletto

Well... who never have done an endless loop in their programing's journey 😅.

Collapse
 
brianl profile image
Brian Lim

It's definitely gotten better over the years

Probably a large reason why a lot of people are still developers or still work with React. Progress seems to be happening.

Collapse
 
juanfrank77 profile image
Juan F Gonzalez

This was a great read. Even though I didn't that many shenanigans with React myself. I still saw them happening with several of my friends and colleagues.

Also, it didn't help the fact that I've been in projects that have used React in the wildest of ways (because they were great monoliths very expensive to update, let alone rewrite)

Needless to say, after React.createClass then extends React.Component and now useEffect and all the possible custom hooks. I don't want anything to do with React anymore.

I still keep getting offers for 'React Developer' but I cannot fathom going again to deal with all of its quirks, reading docs to know what I'm supposed to be doing, and spending time debugging or writing tests with yet another framework.

It's was an interesting ride at least. Not a single moment being boring.

Collapse
 
valeriavg profile image
Valeria

Thank you!
Would you mind sharing some wild ways of using React?
I'm really curious now and the worst I can think of is an innocent jsx-powered NodeJS server.

Collapse
 
juanfrank77 profile image
Juan F Gonzalez

Sure. There was a jsx-powered NodeJS. But there was also the own frontend framework built on top of previous React that had his own server data and a Renderer to take that data an put it into React components. (Who's being used by one of the giants in video streaming service).

There was also the CMS (Drupal) powered, half-static, half-dynamic pages that are being rendered by React but the data comes through a Node server which uses GraphQL to transmit the info from some AWS buckets.

And then there was a project which used Angular 4 to build an entire site for an airplane company, but the catch was... it used micro-frontends with a backend-for-frontend setup.

I don't really which one is worse at this point tbh...

Thread Thread
 
okbrown profile image
Orlando Brown

They are wild indeed!
What would you have done differently?

Collapse
 
squidbe profile image
squidbe

What do you use now?

Collapse
 
rickdelpo1 profile image
Rick Delpo

I spent a good long time on React last year and I found it was a lot of overkill. So I opted for Plain Vanilla JS.

view my article on 17 reasons why at dev.to/rickdelpo1/react-vs-plain-j...

Collapse
 
vassbo profile image
Kristoffer

Nice article. 😃 After I had used plain JavaScript for a few years I wanted to try a framework. The first one was React, it was very hard to figure out. But luckily I found Svelte, the best ever framework! It's so much better in almost every way. 😊

Collapse
 
rytis profile image
Rytis

My experience with React was like this: I've learned it, I liked it, I used it. Then a new version came around and deprecated everything I've learned, suddenly classes are the 'old way' of doing things. I've realized I won't be able to keep up with the pace of modern frontend changes – I can't relearn the framework every 3 months, not unless I'm a full time frontender. So I've completely dropped web frontend from my skills.

Collapse
 
dxniel profile image
Don Daniel

I clicked the link to this post to 'learn more react', I ended up laughing my head off and learning more about 'the micro-evolution of programming' in general. This was an awesome article/post. Best I've read this week.

Collapse
 
valeriavg profile image
Valeria

Thank you very much!

Collapse
 
dailyr profile image
Daily

Thanks for sharing!
For me personally, it was very convenient to use django to build small applications in the past, and it also met daily needs. Since I had the opportunity to contact next.js (based on react), many new concepts and understandings made me find it very interesting and refactored. Some small applications, of course I am not a full-time front-end, it is enough for self-use and project tool construction.

Collapse
 
dailyr profile image
Daily

I was confused about jsx and javascript for a while in the past, now use jsx, Using jsx saves me a lot of trouble

Collapse
 
crenshinibon profile image
Dirk Porsche

I feel with you. I never have and probably never will like React. And actively avoid using it. I used Meteor before there was React and I like to write HTML files with and <style> tags ... and such ... so after a short intermezzo with vue.js now svelte is my goto-framework (naturally).</p>

Collapse
 
samantrags profile image
Raghavendra Samant

Couldn't agree more especially. First 2 paras about comparison with vanilla js. React looks complicated to begin with..

Collapse
 
okbrown profile image
Orlando Brown

The odd thing is, it does not need to be. As engineers we have tendance to be to clever, reinvent the wheel and eventually make life hard for ourselves.

I never understood why developers of all levels apply so much state and transformation logic on the frontend. Just because the language allows it and React inadvertently encourages it does not mean it's the right way to go.

For example a junior developer I manage, challenged me when I suggested moving their business logic into an express app from their frontend SPA (personal project). Asking, why would they need to do that as when they can just call the downstream service as is.

I gently replied, well the bundle size is huge, the app takes way to long to figure it self out before a user can view or know what's going on and your API key to your SaaS provider is exposed for anyone to steal and use, and the list went on...

Moving all the heavy lifting into a BFF and just allowing your SPA to be lightweight view will keep things very simple for you to maintain.

Collapse
 
squidbe profile image
squidbe

the app takes way to long to figure it self out before a user can view or know what's going on

That's the deal breaker. Users are only willing to wait a few seconds before deciding to move on (usually to a competitor).

Collapse
 
valeriavg profile image
Valeria

Couldn't agree more, regardless of the framework, it is possible to setup an efficient structure that will be pleasant to work with.