Managing State in React With Unstated

As your application becomes more complex, the management of state can become tedious. A component’s state is meant to be self-contained, which makes sharing state across multiple components a headache. Redux is usually the go-to library to manage state in React, however, depending on how complex your application is, you might not need Redux.

Unstated is an alternative that provides you with the functionality to manage state across multiple components with a Container class and Provider and Subscribe components. Let’s see Unstated in action by creating a simple counter and then look at a more advanced to-do application.

Using Unstated to Create a Counter

The code for the counter we’re making is available on GitHub:

View Repo

You can add Unstated to your application with Yarn:

yarn add unstated

Container

The container extends Unstated’s Container class. It is to be used only for state management. This is where the initial state will be initialized and the call to setState() will happen.

import { Container } from 'unstated' class CounterContainer extends Container { state = { count: 0 } increment = () => { this.setState({ count: this.state.count + 1 }) } decrement = () => { this.setState({ count: this.state.count - 1 }) }
} export default CounterContainer

So far, we’ve defined the Container (CounterContainer), set its starting state for count at the number zero and defined methods for adding and subtracting to the component’s state in increments and decrements of one.

You might be wondering why we haven’t imported React at this point. There is no need to import it into the Container since we will not be rendering JSX at all.

Events emitters will be used in order to call setState() and cause the components to re-render. The components that will make use of this container will have to subscribe to it.

Subscribe

The Subscribe component is used to plug the state into the components that need it. From here, we will be able to call the increment and decrement methods, which will update the state of the application and cause the subscribed component to re-render with the correct count. These methods will be triggered by a couple of buttons that contain events listeners to add or subtract to the count, respectively.

import React from 'react'
import { Subscribe } from 'unstated' import CounterContainer from './containers/counter' const Counter = () => { return ( <Subscribe to={[CounterContainer]}> {counterContainer => ( <div> <div> // The current count value Count: { counterContainer.state.count } </div> // This button will add to the count <button onClick={counterContainer.increment}>Increment</button> // This button will subtract from the count <button onClick={counterContainer.decrement}>Decrement</button> </div> )} </Subscribe> )
} export default Counter

The Subscribe component is given the CounterContainer in the form of an array to its to prop. This means that the Subscribe component can subscribe to more than one container, and all of the containers are passed to the to prop of the Subscribe component in an array.

The counterContainer is a function that receives an instance of each container the Subscribe component subscribes to.

With that, we can now access the state and the methods made available in the container.

Provider

We’ll make use of the Provider component to store the container instances and allow the children to subscribe to it.

import React, { Component } from 'react';
import { Provider } from 'unstated' import Counter from './Counter' class App extends Component { render() { return ( <Provider> <Counter /> </Provider> ); }
} export default App;

With this, the Counter component can make use of our counterContainer.

Unstated allows you to make use of all the functionality that React’s setState() provides. For example, if we want to increment the previous state by one three times with one click, we can pass a function to setState() like this:

incrementBy3 = () => { this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 })) this.setState((prevState) => ({ count: prevState.count + 1 }))
}

The idea is that the setState() still works like it does, but this time with the ability to keep the state contained in a Container class. It becomes easy to spread the state to only the components that need it.

Let’s Make a To-Do Application!

This is a slightly more advanced use of Unstated. Two components will subscribe to the container, which will manage all of the state, and the methods for updating the state. Again, the code is available on Github:

View Repo

The container will look like this:

import { Container } from 'unstated' class TodoContainer extends Container { state = { todos: [ 'Mess around with unstated', 'Start dance class' ], todo: '' }; handleDeleteTodo = (todo) => { this.setState({ todos: this.state.todos.filter(c => c !== todo) }) } handleInputChange = (event) => { const todo = event.target.value this.setState({ todo }); }; handleAddTodo = (event) => { event.preventDefault() this.setState(({todos}) => ({ todos: todos.concat(this.state.todo) })) this.setState({ todo: '' }); } } export default TodoContainer

The container has an initial todos state which is an array with two items in it. To add to-do items, we have a todo state set to an empty string.

We’re going to need a CreateTodo component that will subscribe to the container. Each time a value is entered, the onChange event will trigger then fire the handleInputChange() method we have in the container. Clicking the submit button will trigger handleAddTodo(). The handleDeleteTodo() method receives a to-do and filters out the to-do that matches the one passed to it.

import React from 'react'
import { Subscribe } from 'unstated' import TodoContainer from './containers/todoContainer' const CreateTodo = () => { return ( <div> <Subscribe to={[TodoContainer]}> {todos => <div> <form onSubmit={todos.handleAddTodo}> <input type="text" value={todos.state.todo} onChange={todos.handleInputChange} /> <button>Submit</button> </form> </div> } </Subscribe> </div> );
} export default CreateTodo

When a new to-do is added, the todos state made available in the container is updated. The list of todos is pulled from the container to the Todos component, by subscribing the component to the container.

import React from 'react';
import { Subscribe } from 'unstated'; import TodoContainer from './containers/todoContainer' const Todos = () => ( <ul> <Subscribe to={[TodoContainer]}> {todos => todos.state.todos.map(todo => ( <li key={todo}> {todo} <button onClick={() => todos.handleDeleteTodo(todo)}>X</button> </li> )) } </Subscribe> </ul>
); export default Todos

This component loops through the array of to-dos available in the container and renders them in a list.

Finally, we need to wrap the components that subscribe to the container in a provider like we did in the case of the counter. We do this in our App.js file exactly like we did in the counter example:

import React, { Component } from 'react';
import { Provider } from 'unstated' import CreateTodo from './CreateTodo'
import Todos from './Todos' class App extends Component { render() { return ( <Provider> <CreateTodo /> <Todos /> </Provider> ); }
} export default App;

Wrapping Up

There are different ways of managing state in React depending on the complexity of your application and Unstated is a handy library that can make it easier. It’s worth reiterating the point that Redux, while awesome, is not always the best tool for the job, even though we often grab for it in these types of cases. Hopefully you now feel like you have a new tool in your belt.

The post Managing State in React With Unstated appeared first on CSS-Tricks.

Solving Life’s Problems with CSS

Or: When all you have is a CSS hammer, the world looks like a CSS nail.

Whenever I hear a perfectly nice comment like, “Yeah, representing the tech field!” in response to my pure-CSS art, I get a sharp feeling of panic.

Like many people who work on excellent post on scooped corners. And it’s an excellent concept to keep in mind when presented with “not possible with CSS” problems. It’s one that I love to use when creating art.

Take, for example, this portion of one of my CSS paintings:

A closeup of a woman's neck that looks like a painting.

The human neck unfortunately does not usually come conveniently packaged in a perfect rectangular shape. But HTML does, so that’s what we have to work with.

But wait, isn’t that neck-shape pretty similar to the curvy black shape that we outlined above?

A series of screenshots that shows the progression of how the formation of the neck started with a simple rectangle and ended with a smooth curvy shape that blends skin-colored gradients together.

Yep, it all started with a big rectangle. In this case, our outward-curving divs just used a softer blending on their box-shadow.

Outside of work, I keep coming back to CSS for artistic inspiration.

Because something about those limitations just calls to me. I know I’m not alone when I say that a rigid set of restrictions is the best catalyst for creativity. Total artistic freedom can be a paralyzing concept.

That can sometimes be the case with programming. If you have the most powerful programming languages in the world at your disposal, it starts to seem natural that you should then have no difficulty solving any programming problem. With all these amazing tools offering countless solutions to solve the same problem, it’s no wonder that we sometimes freeze up with information overload.

Sure, CSS can be thought of as not being a “true” component of the tech stack. I would not even argue against that. Let’s face it, pure CSS is not about recursion or data storage or database-querying. Its primary purpose is indeed for prettification — which doesn’t exactly help the stigma of front-enders not being “real” techies or programmers.

CSS never made any bold claims or promises. It has merely offered assistance, and it just turns out that its assistance can be downright heroic.

If you are a front-ender who has to deal with a bunch of DevOps folks mocking their CSS, just wait and see what the response is when you sneak a body { display: none; } onto production. We’ll see who’s laughing then!*


* They will still be the ones laughing because you will be fired. Please don’t do this.

The post Solving Life’s Problems with CSS appeared first on CSS-Tricks.

Learning Gutenberg: Building Our Custom Card Block

We’ve got some base knowledge, we’ve played with some React and now we’ve got our project tools set up. Let’s dive into building our custom block.

Article Series:

  1. Series Introduction
  2. What is Gutenberg, Anyway?
  3. A Primer with create-guten-block
  4. Modern JavaScript Syntax
  5. React 101
  6. Setting up a Custom webpack
  7. A Custom “Card” Block (This Post)

What we’re building

We’re going to build a custom card block that features an image, a title and a summary. It’s a really common design pattern in the web and it also let’s us look at some core Gutenberg components, along with core WordPress elements, such as the Media Library. We’ll also play with some display logic with JSX for the front-end markup.

Our glorious custom card block!

Our glorious custom card block!

We’re going to focus solely on the the previous section. In your active plugin folder, this is located at blocks/src/block/block.js.

If you are working from the file structure created with create-guten-block, you might want to start by deleting everything in block.js and writing your code from scratch along with the tutorial.

Right at the top of this file, add the following:

const { registerBlockType, RichText, MediaUpload, PlainText } = wp.blocks;
const { Button } = wp.components;

We covered destructuring assignments in Part 2, create-guten-block? In case you need reminding, check it out here. The first six of those were relatively straightforward and involved replacing strings or bit of HTML. The seventh item, “Make the paragraph text editable,” is much more complicated to implement and was intended to get you thinking a bit. The time has come though, and we will indeed make some text editable in Gutenberg!

You may also recognize this registerBlockType function from the PHP register_block_type function we used in the last article. While that function registers a block from the server-side of WordPress, this one registers our block into the React ecosystem on the client side. Both are necessary to have a block that uses React, and their registered names, card-block/main must match.

Add the following code, but make sure you put a comma after 'common', so it looks like this: 'common',.

Here’s the code:

attributes: { title: { source: 'text', selector: '.card__title' }, body: { type: 'array', source: 'children', selector: '.card__body' }, imageAlt: { attribute: 'alt', selector: '.card__image' }, imageUrl: { attribute: 'src', selector: '.card__image' }
}

Here, we are defining the editable attributes of our block and the DOM selector that they are assigned to. This attribute object works in a very similar way to the React state object. It even has a very similar updating method called setAttributes. We’ll get to that later though.

At this point, it’s worth a brief overview of state and attributes because they represent a whole new way of thinking for WordPress developers. I’ll take over for a moment to go over them.

About Attributes and State

It may look like a simple JavaScript object, but that chunk of attributes introduces a whole swath of new concepts to a WordPress theme developer’s brain, not least of which is state. The concept of state has a long history in computer science, and life in general, really. Almost everything has a state. What state is your coffee cup in now? Empty, almost empty? How about your clothing? Are your shoes dirty or new? How about your body? Are you tired or wide awake?

At a high level, state simply refers to the present condition of a thing. In computer science, that thing is a computer program, and that program can be much, much simpler than what we create here on the web. Take a vending machine, for instance. The vending machine has a state that updates each time you put in a coin. When the state of the machine reaches a predefined amount, say $1.25, the machine knows to allow you to make your snack choice.

In Gutenberg, attributes track the present condition of data in a block. Attributes are the closest parallel we can draw to custom fields in Gutenberg, but they exist only in the context of Gutenberg and JavaScript. Let’s take the attribute above for title, for example:

title: { source: 'text', selector: 'card__title'
},

When Gutenberg fires up, it says, “I need to find some text inside a selector called .card__title, and populate the value for title with whatever I find.”

Attributes in Gutenberg are not directly connected to the database like custom fields are connected to post_meta. The entries source and selector are instructions for Gutenberg to populate the state of each block. When we load up the editor, it follows these instructions and assigns a value to title based on the markup saved in the database between the HTML comments that indicate a block of this type. We don’t see the value of title in the attributes we register, but if I were to access props.attributes.title, I would get whatever text exists in .card__title.

We’ve set up some basics, so let’s dive in to our edit function. This is what’s called when the block is accessed from the Gutenberg editor in visual mode. The user will see the rich interface, rather than the HTML code that it generates. That’s what I’ll cover next.

Add our edit function

Let’s add some code in. Add the following after the closing } of the attributes object. Like before, make sure you add a trailing comma, so it looks like this },.

Add the following code after that:

edit({ attributes, className, setAttributes }) { return ( );
}

So, we’re using another destructuring assignment to selectively pick our passed parameters to the edit function. The two most important are attributes and setAttributes. The attributes parameter is the same as the attributes block, but it’s the current, reactive state. This means if the setAttributes function updates one of the attributes values, it will automatically update anywhere that references it, which is similar to our React component from Part 3.

There’s a big ol’ return in this function. Can you guess what’s going in it? Yup! We’re going to stick some JSX in there. Add the following within the return parentheses:

<div className="container"> <MediaUpload onSelect={ media => { setAttributes({ imageAlt: media.alt, imageUrl: media.url }); } } type="image" value={ attributes.imageID } render={ ({ open }) => getImageButton(open) } /> <PlainText onChange={ content => setAttributes({ title: content }) } value={ attributes.title } placeholder="Your card title" className="heading" /> <RichText onChange={ content => setAttributes({ body: content }) } value={ attributes.body } multiline="p" placeholder="Your card text" />
</div>

OK, there’s a lot going on in here, but it’s all stuff we’ve covered in previous parts of this series. What we’ve got here is a container with three existing Gutenberg components. For each, we are setting the relevant attribute as its value, a relevant placeholder and an onChange/onSelect handler. We’re also passing a custom renderer to the <MediaUpload />, which we’ll cover shortly.

Each onChange handler is a handy little expression that passes the new content that triggered the onChange into the setAttributes function, where we set which attributes object to update. This update then cascades into any reference of that attribute, where the content will update like magic. The <MediaUpload /> element features an onSelect event which is fired when the user selects or uploads an item to the media library.

Speaking of the <MediaUpload /> element, you’ll notice there’s a custom render attribute, which references a getImageButton function. Let’s write that next. Above the return in the edit function add the following:

const getImageButton = (openEvent) => { if(attributes.imageUrl) { return ( <img src={ attributes.imageUrl } onClick={ openEvent } className="image" /> ); } else { return ( <div className="button-container"> <Button onClick={ openEvent } className="button button-large" > Pick an image </Button> </div> ); }
};

What this function does is detect if there’s an imageUrl in the attributes object. If there is, it’ll render that <img /> tag and let a user click it to select another. If there’s no image, it’ll render a WordPress <Button /> which prompts the user to pick an image. This calls the same openEvent that was passed into the function.

To keep things simple in this tutorial, we’ve bound a click to the <img /> element. You should consider building something fancy that leverages a <button /> for your production-ready blocks, for better accessibility support.

Right, that’s our edit function done. Not much code there, considering what it actually does, which is great!

Add our save function

We’ve got our Gutenberg editor-end of the block written now, which is the hard part. Now all we’ve got to do is tell Gutenberg what we want the block to do with the content. With the same reactive data from attributes, we can render out our front-end markup in real-time, too. That means when someone switches into HTML editing mode on the block, it’ll be up to date. If you edit it in HTML editing mode, the visual mode will also be kept up to date. Super useful.

Let’s dig in then. After our edit function, add a comma, so it looks like }, and then add the following on a new line:

save({ attributes }) { const cardImage = (src, alt) => { if(!src) return null; if(alt) { return ( <img className="card__image" src={ src } alt={ alt } /> ); } // No alt set, so let's hide it from screen readers return ( <img className="card__image" src={ src } alt="" aria-hidden="true" /> ); }; return ( <div className="card"> { cardImage(attributes.imageUrl, attributes.imageAlt) } <div className="card__content"> <h3 className="card__title">{ attributes.title }</h3> <div className="card__body"> { attributes.body } </div> </div> </div> );
}

Looks pretty similar to the edit function, right? Let’s step through it.

We start of by using a destructuring assignment to pull out the attributes from the passed paramaters, just like the previous edit function.

Then we have another image helper function that firstly detects if there’s an image and returns null if there’s not one. Remember: we return null in JSX if we want it to render nothing. The next thing this helper does is render a slightly varied <img /> tag if there’s alt text or not. For the latter, it hides it from a screen-reader by adding aria-hidden="true" and setting a blank alt attribute.

Lastly, our return spits out a nice .card block with clean, BEM-driven markup that will load on the front-end of our theme.

And that is that for our save function. We’re so close to having a completed block. Just one more step to go!

Add some style

OK, we’ve got this little bit to do and we’re done. The observant amongst you may have noticed some references to className dotted about. These are referencing our editor.scss rules, so let’s add them.

Open up editor.scss, which lives in the same directory as block.js. Add the following:

@import '../common'; .gutenberg { .container { border: 1px solid $gray; padding: 1rem; } .button-container { text-align: center; padding: 22% 0; background: $off-white; border: 1px solid $gray; border-radius: 2px; margin: 0 0 1.2rem 0; } .heading { font-size: 1.5rem; font-weight: 600; } .image { height: 15.7rem; width: 100%; object-fit: cover; }
}

This is some loose CSS to give our block some card-like style. Notice it’s all nested within a .gutenberg class? This is to battle the specificity of some core styles. Within the editor, there is a <div class="gutenberg" wrapped around the block area of the post editor screen, so we can make sure to only affect those elements with this nesting. You’ll probably also notice that we’re importing another Sass file, so let’s fill that one.

Open common.scss which lives in the src directory, which is the parent of the current block directory that we’re in.

/* * Common SCSS can contain your common variables, helpers and mixins * that are shared between all of your blocks. */ // Colors
$gray: #cccccc;
$off-white: #f1f1f1;

Anyway, guess what? We’ve only gone and built out a custom card block!! Let’s give it a test-drive.

First, check your block is all-good. This is what the complete block.js file should look like:

const { registerBlockType, RichText, MediaUpload, PlainText } = wp.blocks;
const { Button } = wp.components; // Import our CSS files
import './style.scss';
import './editor.scss'; registerBlockType('card-block/main', { title: 'Card', icon: 'heart', category: 'common', attributes: { title: { source: 'text', selector: '.card__title' }, body: { type: 'array', source: 'children', selector: '.card__body' }, imageAlt: { attribute: 'alt', selector: '.card__image' }, imageUrl: { attribute: 'src', selector: '.card__image' } }, edit({ attributes, className, setAttributes }) { const getImageButton = (openEvent) => { if(attributes.imageUrl) { return ( <img src={ attributes.imageUrl } onClick={ openEvent } className="image" /> ); } else { return ( <div className="button-container"> <Button onClick={ openEvent } className="button button-large" > Pick an image </Button> </div> ); } }; return ( <div className="container"> <MediaUpload onSelect={ media => { setAttributes({ imageAlt: media.alt, imageUrl: media.url }); } } type="image" value={ attributes.imageID } render={ ({ open }) => getImageButton(open) } /> <PlainText onChange={ content => setAttributes({ title: content }) } value={ attributes.title } placeholder="Your card title" className="heading" /> <RichText onChange={ content => setAttributes({ body: content }) } value={ attributes.body } multiline="p" placeholder="Your card text" formattingControls={ ['bold', 'italic', 'underline'] } isSelected={ attributes.isSelected } /> </div> ); }, save({ attributes }) { const cardImage = (src, alt) => { if(!src) return null; if(alt) { return ( <img className="card__image" src={ src } alt={ alt } /> ); } // No alt set, so let's hide it from screen readers return ( <img className="card__image" src={ src } alt="" aria-hidden="true" /> ); }; return ( <div className="card"> { cardImage(attributes.imageUrl, attributes.imageAlt) } <div className="card__content"> <h3 className="card__title">{ attributes.title }</h3> <div className="card__body"> { attributes.body } </div> </div> </div> ); }
});

If you’re happy, let’s fire up webpack. While in your current plugin directory in terminal, run this:

npx webpack --watch

This is slightly different to the previous part in the series because we’ve added the --watch argument. This basically keeps an eye on your js files and re-runs webpack if they change.

Fire up the editor!

Let’s fire up the Gutenberg editor by loading up a post in the WordPress back end. In the Gutenberg editor, click the little plus icon and look in the “blocks” tab and there it is: our awesome new card block!

Go ahead and give it a test drive and add some content in there. Feels good right?

Here’s a quick video of what you should be seeing right now, with your fancy new card block:

And with that, you’re done 🎉

Here’s a thing you might be thinking: Aren’t blocks kind of a replacement for custom fields? Can’t I now create my own content structure directly within WordPress instead of using a plugin like Advanced Custom Fields? Not quite…

Blocks vs. Custom Fields

While Gutenberg does afford us the ability to customize the structure of data entry from the user’s experience, on the back-end it’s no different than the current WYSIWYG editor. Data saved from a block is part of the post_content column in the wp_posts database table—it’s not stored separately in wp_postmeta like custom fields. This means that, at present, we cannot access the data from our card block from another post in the same way we could if we had created custom fields for title, image and content with a standard Advanced Custom Fields setup.

That said, I could see some really interesting plugins surfacing that provide a way to port data from a block to other parts of a website. With the WordPress REST API, the possibilities are just about limitless! In our screencast, Andy and I took a stab at incorporating an API request into our card block and, although things didn’t turn out exactly as planned, the tools are already in place and you can get a taste of what could be possible with Gutenberg in the future. Time will tell!

Wrapping up and next steps

What a journey we’ve been on together! Let’s list out what you’ve learned in this series:

  • You’ve learned some core, modern JavaScript by getting to grips with ES6
  • You’ve learned the basics of JSX
  • You took that new knowledge and built out a React component from scratch
  • You then learned how webpack works and wrote a scalable config file for Gutenberg block development
  • Finally, you built custom Gutenberg card block from scratch

So, where can you go from here? Now that you’ve got some solid base knowledge from this series, you could do some further learning. There’s already fantastic resources for that:

  • Writing Your First Block Type on WordPress.org (Andy: That’s how I learned how blocks work)
  • Gutenberg Courses by Zac Gordon and Joe Casabona
  • Creating a Custom Gutenberg Block by Pete Tasker
  • Anatomy of a Custom Block by Morgan Kay
  • One Thousand and One Ways to Extend Gutenberg Today by Riad Benguella
  • Gutenberg talks on WordPress.tv

Some interesting case studies:

  • Auditing Your WordPress Plugin for Gutenberg
  • Gutenberg on Humanmade.com
  • Modern Tribe’s “Going Gutenberg”

Keep an eye on these resources to stay up to date with the project:

  • Gutenberg News
  • Gutenberg Times

Experimental things happening with Gutenberg:

  • Gutenberg Custom Fields plugin
  • Atomic Blocks plugins and theme

Once Gutenberg becomes part of WordPress core in version 5.0 (release date TBD), you could also publish a useful custom block in the WordPress plugins directory. There’s definitely room for some handy components such as the card block that you’ve just built.

We hope you’ve enjoyed this series, because we’ve certainly enjoyed making it. We really hope this helps you get into Gutenberg and that you build some cool stuff. You should totally send us links of stuff you have built too!


Article Series:

  1. Series Introduction
  2. What is Gutenberg, Anyway?
  3. A Primer with create-guten-block
  4. Modern JavaScript Syntax
  5. React 101
  6. Setting up a Custom webpack
  7. A Custom “Card” Block (This Post)

The post Learning Gutenberg: Building Our Custom Card Block appeared first on CSS-Tricks.