惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Spread Privacy
Spread Privacy
T
Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
MongoDB | Blog
MongoDB | Blog
V
Vulnerabilities – Threatpost
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Help Net Security
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
小众软件
小众软件
Cloudbric
Cloudbric
The Hacker News
The Hacker News
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
人人都是产品经理
人人都是产品经理
Forbes - Security
Forbes - Security
Martin Fowler
Martin Fowler
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
AWS News Blog
AWS News Blog
Stack Overflow Blog
Stack Overflow Blog
N
News | PayPal Newsroom
P
Privacy & Cybersecurity Law Blog
TaoSecurity Blog
TaoSecurity Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园_首页
A
Arctic Wolf
www.infosecurity-magazine.com
www.infosecurity-magazine.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Scott Helme
Scott Helme
T
Tor Project blog
S
Secure Thoughts
Know Your Adversary
Know Your Adversary
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
博客园 - 司徒正美
T
Threat Research - Cisco Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
Schneier on Security
Schneier on Security
B
Blog RSS Feed
AI
AI
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Attack and Defense Labs
Attack and Defense Labs
Webroot Blog
Webroot Blog
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
Hacker News: Ask HN
Hacker News: Ask HN

ValeriaVG

Agentic Development Survival Guide Simplicity Police The sunset of Arrogance as a Service How do I delegate when I can do it faster myself? Implementing custom Calendar component Plug & Play Modular Architecture for Scalable and Maintainable Apps ES Modules & Import Maps: Back to the Future 10 Reasons NOT to Use Go for Your Next Project How Build a Web App in 11 Minutes and Fall in Love With Sveltekit Master Git in 7 Minutes Crc 32 Checksum in Wasm and Raw Js Tutorial and Benchmark Master Binary in Five Minutes Five Pro Tips to Master Promises in Js How to Use Custom Files as Modules in Nodejs How to Do Magic With Numbers 5 Ways to Use Redis in Your Next Project
Me & React: 5 Years in 15 Minutes
Valeria Viana Gusmao · 2022-09-08 · via ValeriaVG

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>

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>

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"));

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"));

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"));

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"));

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"));

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"));

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"));

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"));

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"));

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"));

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);

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"));

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"));

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 :-)