Isn’t React for engineers? I love this question. Because not too long ago, the question was: “Isn’t programming for engineers?”. This implies that we’ve since established that it isn’t. You don’t have to be an engineer to code. And you need “enough code to be dangerous” to greatly increase your potential for complex creative expression. When designers talk about code, it’s most often in the context of designing interfaces. And the way we think of interface composition is in elements, like buttons, lists, navigation, etc. React is an optimized way to express interfaces in these elements, through components. It helps you build complex interfaces (and even simple interfaces get complex quickly) in an efficient way. By organizing your interfaces into three key concepts— components, props, and state—you can express anything you can think of and get all these things easily: Clear structure and rules to help organize your code, so you don’t have to start over at a certain complexity.

A way to isolate, compose, and re-use parts of your code between projects and across teams in the form of simple components or even complex design systems.

Good rules to collaborate with others, as everything is built in a similar way. React is a smart way to organize old interface code using simple concepts and rules. Saying that it‘s only useful for engineers would be like saying that no amateur photographer should ever buy a Leica. If you have the opportunity, why not work with the best tools?

Why does React seem so hard? I’ve noticed that designers with experience building interfaces in jQuery, ActionScript, or (ironically) Framer Classic tend to struggle with React. This has little to do with React and everything do to with programming models. The examples mentioned above use an imperative model, while React uses a declarative model. Let me explain the difference… Imperative model Much like giving someone step-by-step directions to cook a dish, an imperative model requires you to describe the exact steps to achieve a change. Declarative model A declarative model describes changes as before and after and lets the computer figure out the steps in between...much like ordering your custom frappuccino. As designers, we’re used to working declaratively. Every timeline application where you tween between two states is a fantastic example. You describe before and after, and the computer figures out the tween. Let’s try to look at this from a programmer’s perspective and build a simple login flow. This is not real or complete code, it just tries to illustrate the difference in approach. The imperative app uses (fake) jQuery to describe exactly what to change if something happens. This should look familiar if you’ve used it a lot. $ ( "button .login" ) . onClick ( ( ) => { $ ( "form" ) . attr ( "enabled" , false ) $ ( "body" ) . append ( $ ( "div.spinner" ) ) doLogin ( ( success , username ) => { if ( success ) { $ ( "form" ) . remove ( ) $ ( "div.spinner" ) . remove ( ) $ ( "body" ) . append ( $ ( ` Welcome back ${ username } ` ) ) } else { $ ( "form" ) . attr ( "enabled" , true ) $ ( "form.error" ) . text ( "Could not login" ) $ ( "div.spinner" ) . remove ( ) } } ) } ) COPY $("button .login").onClick(() => { $("form").attr("enabled", false) $("body").append($("div.spinner")) doLogin((success, username) => { if (success) { // Remove the form and show login $("form").remove() $("div.spinner").remove() $("body").append($(`Welcome back ${username}`)) } else { // Stop the spinner and enable form again $("form").attr("enabled", true) $("form.error").text("Could not login") $("div.spinner").remove() } }) }) The declarative (fake) React code describes the three different states of the app: logged_out, logging_in and logged_in. It seems to completely re-render your app at every change, but the trick is that under the hood it figures out all the differences and only updates those so that everything stays as fast as possible. function App ( { state = "logged_out" , username = null } ) { if ( state === "logged_out" ) { return < Login /> } if ( state === "logging_in" ) { return < Spinner /> } if ( state === "logged_in" ) { return < div > Welcome back { username } </ div > } } COPY function App({ state = "logged_out", username = null }) { if (state === "logged_out") { return <Login /> } if (state === "logging_in") { return <Spinner /> } if (state === "logged_in") { return <div>Welcome back {username}</div> } } I hope these examples have illustrated why the declarative model makes a lot of sense for building interfaces. It does require a bit of a mind-shift if you have gotten used to the imperative model, but it’s ultimately worth it.

What is application state? Now state can refer to many things. Animators see it as a visual configuration at a specific moment in time, explicitly defined. Web designers think of it as events that trigger a CSS class like hover, press, or loading. But React was defined by engineers and they think of state as the current internal state of your application, which is defined as what you see on the screen. So in other words, state is all the variables that make up your application. Let’s look at some visual examples. Let’s assume this card is my entire app for now. To draw it with real data I need 7 variables in total: profile_image_url, name, handle, tweets_count, tweets_images following_count and followers_count. So if I were to describe the state in JavaScript it would look something like this: { profile_image_url : "koen.jpg" , name : "Koen Bok" , handle : "@koenbok" , tweets_count : 5869 , tweets_images : [ "motion.jpg" , "switch.jpg" , "react.jpg" ] , following_count : 2181 , followers_count : 11400 } COPY { profile_image_url: "koen.jpg", name: "Koen Bok", handle: "@koenbok", tweets_count: 5869, tweets_images: ["motion.jpg", "switch.jpg", "react.jpg"], following_count: 2181, followers_count: 11400 } You see that these variables let me make every possible combination for this card. Much like a cold email template with variables Hello #{first_name} let's meet for coffee. But a full application state has way more things; from dynamic views to login fields. So let’s zoom out a little and look at an entire application state for a Twitter app. Suddenly, there’s a lot more going on. Navigation tabs, logins, feed with loading, search etc. But nothing really changes in our approach. The state just becomes more extensive. Let’s look at what we would need to add to the above to describe the full Twitter interface state: { logged_in : true , selected_tab : "feed" , search_query : null , tweet : null , feed_loading : false , feed : [ { id : 456 , name : "Krijn Rijshouwer" , tweet : "Say hello to" ... } , { id : 123 , name : "Ryan Florence" , tweet : "React gave me..." ... } , ] } COPY { //... all of the above logged_in: true, // if not, we need to show a login screen selected_tab: "feed", // these can be `notifications` or `messages` too search_query: null, // maybe we're doing a search tweet: null, // or we might be writing a new tweet feed_loading: false, // so we can show a spinner feed: [ { id: 456, name: "Krijn Rijshouwer", tweet: "Say hello to" ... }, { id: 123, name: "Ryan Florence", tweet: "React gave me..." ... }, // And many more tweets, things get added if you scroll down ] } You can see how these are all the variables that we need to show the application, neatly stored together. If we were to now write some interface code, it would look something like this (for simplicity’s sake, I’ve left some things out): function Twitter ( state ) { if ( ! state . logged_in ) { return < div > Login : < input /> </ div > } const feed = state . feed . map ( item => ( < div > { item . name } : { item . tweet } </ div > ) ) ; return ( < div > < button enabled = { state . selected_tab !== "feed" } > Feed </ button > < button enabled = { state . selected_tab !== "notifications" } > Notifications </ button > < button enabled = { state . selected_tab !== "messages" } > Messages </ button > { state . feed_loading ? < div > Loading </ div > : feed } </ div > ) ; } COPY function Twitter(state) { // If we are not logged in, we show a login screen if (!state.logged_in) { return <div>Login: <input /></div> } // Build the feed from tweets to use below const feed = state.feed.map(item => ( <div>{item.name}: {item.tweet}</div> )); return ( <div> <button enabled={state.selected_tab !== "feed"}>Feed</button> <button enabled={state.selected_tab !== "notifications"}>Notifications</button> <button enabled={state.selected_tab !== "messages"}>Messages</button> {state.feed_loading ? <div>Loading</div> : feed} </div> ); } This is obviously an extremely simplified version, but if you have built prototypes before this should look really familiar. We really cleanly separated state and interface logic. And now comes the magic moment (I hope). For me, this is the point where React really started to click. Look at the code again and notice how… simple it all is. Think about when you were building something similar in jQuery or Flash. You were likely writing a ton of: $ ( "#feed" ) . click ( function ( ) { $ ( "#feed" ) . attr ( "enabled" , true ) $ ( "#notifications" ) . attr ( "enabled" , false ) $ ( "#messages" ) . attr ( "enabled" , false ) } ) COPY $("#feed").click(function() { $("#feed").attr("enabled", true) $("#notifications").attr("enabled", false) $("#messages").attr("enabled", false) }) They all change the page a bit and update the state. But where is the state? It’s embedded in the page, and built up over time through all the functions that cause it to change. So when you eventually run into an unexpected state (and you will) it’s really hard to easily get an overview of the state, let alone reason or reproduce it so you can debug. React always forces you to cleanly separate state and update it at once. That way you can write extremely simple code and avoid many bugs. It’s an extremely pleasant way to work. And it’s the main reason React (and other declarative component frameworks) are dominating. To fully close the loop, let’s see how engineers look at (and talk about) this. This part isn’t needed to get work done, but it does seems like a pity to get this far and not also try to explain some of the very-accurate-but-deliberately-hard-sounding engineering terminology. Don’t worry if you don’t get this part (or don’t care). So if you just take the Tweet function and completely empty it out you get: function Tweet ( state ) { return output } COPY function Tweet(state) { return output } // Where output is the app html Or even more simplified in a mathematical notation: output = app ( state ) COPY output = app(state) // x = f(y) Your application is a function of your state. Every time you insert the same state, you get the exact same output. You always render your entire app as a whole, so it’s extremely easy to reason about and React makes sure it’s still fast through only actually updating the changes. If you want to go deeper on this concept I recommend Pure UI by Guillermo Rauch .

What are props and state? This is likely the most often asked React question because it confuses so many people. But it’s honestly very simple, especially if you know some HTML. Before getting into the theory, let me show you using code. I’ll start with props because you almost always need props, but you definitely don’t always need state. < img src = " test.jpg " width = " 100px " height = " 100px " /> COPY <img src="test.jpg" width="100px" height="100px" /> This element has three props: src, width and height. In HTML you would call them attributes. Programmers often call these properties; React just shortened it to props. That’s all there is to it. Let’s say you would write your own special square image element in React, you get these passed in so you can use them: function SquareImage ( { src , size } ) { return < img src = { src } width = { size } height = { size } /> } < SquareImage src = " test.jpg " size = " 100px " /> COPY function SquareImage({ src, size }) { return <img src={src} width={size} height={size} /> } // Component usage <SquareImage src="test.jpg" size="100px" /> So props are just the attributes of your components. You use them to configure your components and it’s how components get values passed in from the outside. This last part is the key difference with state. Because sometimes your component only needs values within the component itself. That sounds weird but think, for example, about a hover state that changes text. The component itself responds to the hover state, and changes its own text. function Hovercraft ( ) { const [ text , setText ] = useState ( "Craft" ) const mouseOver = ( ) => setText ( "Hover" ) const mouseOut = ( ) => setText ( "Craft" ) return < div onMouseOver = { mouseOver } onMouseOut = { mouseOut } > { text } </ div > } < Hovercraft /> COPY function Hovercraft() { const [text, setText] = useState("Craft") // Default is Craft const mouseOver = () => setText("Hover") const mouseOut = () => setText("Craft") return <div onMouseOver={mouseOver} onMouseOut={mouseOut}>{text}</div> } // Component usage <Hovercraft /> No outside values required, so we’re not using props, just state. It just needs a text value and that is only changed by the component itself. You can obviously mix props and state as needed.

Hooks and State Hooks are a hip name for things you can do in a component. The most common one that you will run into is useState. It allows the component to remember some value, and update when it changes. The syntax may look a bit scary at first, but it’s really not that hard. const [ scale , setScale ] = React . useState ( 1 ) COPY const [scale, setScale] = React.useState(1) What this does is it sets the scale variable to the value 1. Much like: const scale = 1 COPY const scale = 1 So why all that other stuff? Well, when you change this scale in the future, you want to ensure the component changes with it, so it needs to update itself on the screen. In short, for React to know the value is updated, it needs a hook. This is where the React.useState(1) comes in. It lets React know: Hey React! You want to keep an eye on this value here.

Oh by the way the default value for it is 1. React: no problem! I’ll keep track of it. Here you have two things back: The current value for scale (which is 1 if you never changed it).

A function to update the value so that I know about it too, called setScale. So the complicated looking const [scale, setScale] is just needed because React gives you back two things instead of one, and this little shortcut is a nice way to give them both names. You could actually write the exact same code without the shortcut like this: const hook = React . useState ( 1 ) const scale = hook [ 0 ] const setScale = hook [ 1 ] COPY const hook = React.useState(1) const scale = hook[0] // First value const setScale = hook[1] // Second value Whew, ok. I hope this is enough information to convince you to start using the shortcut. The last thing we need to look at is how to change the scale value with setScale. Let’s do that with a full example: function MyComponent ( ) { const [ scale , setScale ] = React . useState ( 1 ) return < Frame scale = { scale } onTap = { ( ) => setScale ( 2 ) } /> } COPY function MyComponent() { const [scale, setScale] = React.useState(1) return <Frame scale={scale} onTap={() => setScale(2)} /> } Pretty easy; if you tap the scale gets set to 2 using setScale and React updates the component. To finish off, I’ll show you almost the same but now a little bit more explicit using the function notation I used before. This is mostly a preference, you can pick what you like better. Additionally, this example will increase the scale by 0.1 every time you tap. function MyComponent ( ) { const [ scale , setScale ] = React . useState ( 1 ) function onTap ( ) { setScale ( scale + 0.1 ) } return < Frame scale = { scale } onTap = { onTap } /> } COPY function MyComponent() { const [scale, setScale] = React.useState(1) function onTap() { setScale(scale + 0.1) } return <Frame scale={scale} onTap={onTap} /> } A little more code, but a little simpler looking maybe. Again, up to you. But I like this. Here is a pretty great intro if you like to learn more about hooks and build something real.

Class or function components? There are two ways to define components in React: functions and classes. Until the recent React Hooks release, class-based functions gave you more features for your components. But thanks to React Hooks they can now both do everything, so most people stopped using class-based components. class KoenComponent extends React . Component { render ( ) { return < div > Hello world ! </ div > } } function KoenComponent ( ) { return < div > Hello world ! </ div > } COPY // Class based component class KoenComponent extends React.Component { render() { return <div>Hello world!</div> } } // Function based component function KoenComponent() { return <div>Hello world!</div> } We built the new Framer library on React Hooks because it is simpler and ensures that beginners won’t have to learn about classes, this, etc right off the bat. It’s quite elegant really. TLDR; use functions and learn about Hooks if you plan to get more advanced with React.