The new PlayStation 5 logo has been revealed, to much fanfare, at CES 2020. To say the moment was an anticlimax would be an understatement. In short, the new PS5 logo looks exactly like the old PS4 logo. Which, to be fair, looked an awful lot like the PS3 logo. See it in all its glory above.
Sony has been slowly releasing information about its next console over the past few months. It’s due to be released “Holiday 2020”. Sadly, this latest revelation wasn’t quite as exciting as we might have hoped – Sony has clearly decided the logo wasn’t broke, and no fixing was required (for more enduring brand marks, check out our guide to the best logos of all time).
We quite like that the new logo gives the impression that it’s just the ‘2’ of the PS2 logo reversed and flipped (it’s not, incidentally, the PS2 logo was a whole lot more angular), but other than that there’s not really much to say.
PlayStation logos through the years (Image credit: Sony)
If Sony execs thought this was a safe design choice that wouldn’t attract too much vitriol from the PlayStation community, they were sorely mistaken. The claws are out and the memes are rolling in fast. Read on for our pick of the most savage takedowns so far (you might also want to check out Twitter’s hilarious reaction to the Xbox Series X last month).
Many commenters are calling out Sony for being lazy…
Sony’s lead graphic designer coming up with the #PS5 logo#SonyCES pic.twitter.com/7xOJXBWHCFJanuary 7, 2020
You had one job Sony! #PS5 #PlayStation5 #SonyCES pic.twitter.com/jZVx4cZMQZJanuary 7, 2020
Don’t tell Sony but they accidentally emailed me the PS6 logo by mistake pic.twitter.com/gFHb4D6B4CJanuary 7, 2020
… but Mike Drucker’s tweet is probably a little closer to the truth.
The funniest part of the PS5 logo being identical to the PS4 logo is you *know* there were HOURS of meetings and discussions and notes and follow up calls and approvals for this design https://t.co/V9KLZCctbhJanuary 7, 2020
Or are there hidden messages that we’re missing?
If you turn the PS5 logo upside down it spells SSD which means – and this is pure speculation – it will contain an SSD. pic.twitter.com/WfXL2lTbkpJanuary 7, 2020
On October 14, 2015, I hosted the inaugural React Vancouver meetup. It was at a point were I had used React for the better part of the year and wanted to bring like-minded developers together.
React back then was, dare I say it, revolutionary in the web frontend world. Compared to the alternatives such as jQuery, Backbone.js or Angular 1.x, developing with React felt intuitive, refreshing and productive. Personally, the idea of isolated building blocks (aka components) really appealed to me as it naturally led to a structured, well organized and more maintainable code base.
Over the coming years, I kept a close eye on Angular 2.x , Vue et al but none felt like a wortwhile choice to jump ship.
Then I learned about Svelte
I first learned about Svelte in mid 2018, almost a year before version 3.0 was released (see below). “Computer, build me an app.” by Rich Harris is what got me hooked on Svelte.
If you’re not familiar with Svelte (https://svelte.dev/), please go to the website and spend 5 minutes reading the intro.
Read it? Really? Excellent ?
Once I watched the video, the main question in my mind was whether or not it’s worth learning Svelte and starting to use it for new or even existing projects. In all fairness, Svelte impressed me but it still wasn’t enough to embrace it fully.
Please take some time to read the blog post and watch the video – it’s about spreadsheets but I promise it’s fun ?
Why was this such a big deal? For one, the Svelte team had been talking about version 3 quite a bit and I wanted to see it in action. On the other hand, Svelte and its promise excited me even more than React did when first I heard of it.
I mentored web developers at that time and had spent quite a bit of time bringing them up to speed on React. Things like JSX, CSS-in-JS, Redux, create-react-app, SSR and other concepts needed to be learned, understood and to a certain degree mastered in order to develop React apps.
None of that was necessary with Svelte.
Hello {name}!
App.svelte
Simple enough? I agree. In fact, it is so simple I recommend it to my mentees who are new to web development.
Real quick, what’s going on in that code?
The script tag is where the component’s logic lives.
The style tag defines this component’s CSS – none of this leaks outside the component, so we can safely use h1 and it only applies to this component. It’s real CSS, not a Javascript object that pretends to be CSS or a string literal that pretends to be CSS.
At the bottom is the component’s HTML. Use variables with {myVariable}. Compared to React’s JSX, Svelte allows you to use the correct HTML tags such as for, class instead of forHtml and className. See “Differencs In Attributes” in the React documentation for a list of all attributes that are not standard HTML.
Let’s rebuild React examples
To give you an idea of what Svelte looks like compared to React, let’s rebuild what’s listed on https://reactjs.org/.
Whenever you have variables that depend on other variables, declare them with $: myVariable = [code that references other variables]. Above, whenever count changes, doubled gets recalculated automatically and the UI updates to reflect the new value.
Stores
In cases where state needs to be shared across components, Svelte provides the concept of stores. The tutorial explains stores well. No need to read lengthy tutorials – stores are that simple.
Derived stores
Often, one store depends on other stores. This is where Svelte provides derived() to combine stores. See the tutorial for details.
Await as a logic block
Alright, this one is a quite elegant. Let’s start with the code (interactive demo):
{#await githubRepoInfoPromise}
...loading
{:then apiResponse}
{apiResponse ? `${apiResponse.full_name} is written in ${apiResponse.language}` : ''}
{:catch error}
{error.message}
{/await}
See the #await block in the HTML? In a real-world application, you’d have a Loading component, an error component and the actual component to render the API response in this case. Try to enter an invalid repo name in the text box to trigger the error case.
“But wait, what about…”
open source components?
The main response I get when I introduce Svelte to someone is “but what about the ecosystem, components, tutorials, tools, etc?”
Yes, there are nowhere near as many open source Svelte components as there are components for React. Having said that though, how often do you take an open source React component and integrate it without any issues or unnecessary overhead? I’d argue many of us in the Javascript community have become too reliant on npm install ... to piece together a web application. Often building your own components, especially in Svelte, leads to less time spent overall. I have no data to proof that, it’s base on my personal experience.
Related though, there is a growing list of Svelte components for anyone who sees comfort in reusing open source components.
Also remember, the competition is much smaller compared to applying for a job that requires React, Vue, Angular, etc.
And then, there’s Sapper to deploy Svelte apps
Developing an app is only a piece of the full cake – the app also needs to be deployed. For this, the Svelte team provides Sapper. That’s an entire post in itself, so for now please have a look at the website for details.
Conclusion
That brings me to the second part of this blog’s title, “why others will follow.” Every day, new web developers start their journey and the first thing many hit is an uncertainty of what to learn first. I say the future is about simplicity, quick time to market and I can’t think of anything simpler and quicker than this:
Hello {name}!
Do hit me up on Twitter @mikenikles with your feedback.
You can learn how to use the terminal in a fairly short amount of time. You don’t need a C.S. degree. You don’t need to know how to hack any mainframes.
With the terminal, you can open, move, rename, copy and delete files. Same with directories (folders). The terminal is the Finder app on steroids. File management is just the start. The terminal is the interface for a slew of power tools.
You can install and run programs.
You can version files.
You can read documentation offline.
You can write scripts to automate tasks.
You can edit programs.
You can configure hidden OS settings.
You can tunnel into servers.
You can take full advantage of open source resources.
If you’re using React, you can quickly spin up applications and install design systems.
If you’re using git you can contribute to the execution of your design work.
The terminal is a powerful tool.
It’s a powerful tool for designers.
It’s a powerful tool for anyone.
Make it look nice
The Terminal can also be a bit daunting.
I recommend making it look nice first. Download a nice theme.
Extract the zip file, and import it into your terminal.
Open Terminal. CMD, to open up settings.
Import the .terminal file and set it to default.
Restart the Terminal.
If you aren’t happy with the default monospace font, there are plenty of good options to choose from:
The Terminal helps you move around and modify the file system.
Here are 7 commands that are important as you get started:
1. List — ls
ls shows the files and directories in your current directory.
2. Change Directory — cd
cd is how you move around. cd .. will take you to the parent directory. cd Documents will take you into the Documents directory. For this to work, you need to be currently in a location that contains a Documents directory.
3. Move — mv
mv is used to move files from one directory to another. mv file.txt new/file.txt moves a file from your current directory to the new directory. mv file.txt new.txt will rename file.txt to new.txt.
4. Create — touch
touch is used to create files. touch hello.md creates a file named hello.md in your current directory.
5. Make Directory — mkdir
mkdir creates a directory. mkdir images creates a directory named images in your current directory.
6. Remove — rm
rm removes a file. rm -d removes a directory. rm -rf node_modules will recursively delete the node_modules directory and every file/directory inside of it. Most commands you run in your terminal are harmless. Be careful with this command. Deleted objects aren’t stored in Trash, and there’s no undo.
7. Open — open
open will open a file in the using the default program for that file type. open index.html will launch your default browser with the html page in the location bar. open README.md will open up your default markdown editor.
Important Locations
If you’re on a Mac some locations have a shorthand.
/ is shorthand for your root directory. ~ is shorthand for your user directory. . is shorthand for your current directory.
You can change directory from any location into your user (cd ~) or root (cd /) directory by using these shorthand locations.
Additionally, cd without a provided location will move you into your user directory.
You can use a tool like bashmarks to save and visit commonly used directories.
Typing long location names gets old. In addition to shorthand, you can autocomplete locations using tab.
Custom Prompts and Commands
By default your Terminal includes computer and user information in the prompt.
Philips-MacBook:Documents philipdavis$
It’s common to remove this and replacing it with the current location followed by a $ sign.
To do this, we need to edit a .bash_profile file (.zprofile if you’re running MacOS Catalina) which allows us to customize our terminal further.
The .bash_profile file is located in the home ~ directory. If you run ls and you don’t see it, it’s because it’s a dot file.
Dot files are hidden by default, but we can see them if we add parameters to our ls command.
Parameters for terminal commands are often passed after a - dash. ls -alhG shows you all files (including dot files) in an easier to scan format, with file size and colorized folders.
This is what the normal ls looks like.
And now with the additional parameters.
If you don’t see a .bash_profile in your home directory, you will need to create it.
Once you have the file you can open it in a text editor.
Once the file is opened, you can add the following string to replace the prompt cruft (computer name, location and user) with the location and a money $ sign.
In addition, instead of remembering all the parameters for ls -alhG you can add an alias so that ls uses it by default.
Save the .bash_profile file, run source ~/.bash_profile and then restart the terminal to start using the new settings.
You can create aliases for any commands that you commonly use.
I’ve created aliases for scaffolding react applications, and starting node applications. Here’s what your .bash_profile might look like after you’ve added your own custom aliases.
export PS1="W $ "
alias ls="ls -alhG"
alias ns="npm start"
alias cra="create-react-app"
The Power Tools
In additional to basic shell commands there are a number of powerful tools that allow you do more in your terminal. I’ve listed a few below. Each takes time to learn. Each has something valuable to offer.
git for versioning and collaboration. npm or yarn for installing and versioning node modules. homebrew for installing programs and applications. ssh for tunneling into servers. vim for editing files in the terminal. create-react-app for scaffolding react applications
Piping and Chaining
By default, output from your terminal is displayed in your terminal. You can reroute the output of a command to another file or to your clipboard by using the pipe command |.
Here we are running base64 on an image which converts it to a data URI. We are then copying the data URI to our clipboard. pbcopy and pbpaste are the commands to copy and paste in terminal.
You can use the && operator to chain commands. This is useful when you need to wait for commands to execute. The && operator acts as a queue. If the first command successfully executes the second will begin running.
npm install && atom . && npm start
Here, when npm install is finished, atom will open with the current directory loaded and then npm start will run.
sudo GoForthAndH4ck.exe
The terminal is a powerful application but it doesn’t need to feel intimidating.
If you have questions about using the terminal, or just want some guidance getting set up, please reach out to me.
Numerous organizations these days are switching to a “mobile-only” model for their online business. They prefer to keep their maintenance low and keep user experience perfect at the same time. With a standalone mobile application, the user is able to perform almost every activity right from the mobile application. Although organizations now have the benefit of not having to manage a website, they still need to build applications for different mobile OS.
As a result, Hybrid application development technology like React Native is on the rise. React Native enables the developer to build an application for multiple OS using a single codebase. With the power of React Native, the developers are able to simplify the complete mobile application development. The normal mobile application architecture is split into three major parts:
In a competitive, cut-throat market, developing applications in a cost-effective manner is very important. With React Native applications, the frontend development has surely been simplified. However, backend development and storage management still pose challenges.
In this article, we guide you with an approach to resolve this problem with the help of ButterCMS.
1. Understanding the need for the backend
Backend development handles behind the scene functionality of an application. The code connects the mobile application to a database, manages user interactions, and powers the application itself. The back-end works in tandem with the front-end to present the final product to the end-user.
With the onset of mobile apps, the current shift not only includes developing an efficient application frontend but also a well-optimized backend. The mobile backend development task ensures proper database design, scripting, and the architecture of the application. The primary purpose of the backend is to run continuously and listen to the user requests while serving back the response as needed.
The mobile application backend can perform multiple tasks like serving static files, processing data requests, authorizing the user requesting for data and providing APIs for data transactions. These operations could take variable time depending on the complexity of the required features. Moreover, just like we build the frontend of every application from scratch, in most cases, the backend is built from scratch too.
2. Identifying the components around mobile applications
Now, let us try to understand the minimum components required around the mobile application to make sure it runs. A mobile application is normally packaged in the form of a setup file that installs onto the mobile device. This application package can contain the majority of the static data that would be required by the mobile application.
In order to render and process dynamic data or inputs, the mobile application would require three major components:
Static file server for mobile application
A static file server provides the static files to the mobile application remotely. This server is required normally to keep the installation package size smaller than usual. With a static file server, a mobile application can easily download files from the server over the internet when it is being used.
Backend Data-processing server
A backend server for mobile applications will provide API endpoints for the mobile application. The mobile application can request the server for data exchange and the backend server will process the same and send the corresponding response. The majority of the time, companies focusing on mobile application based business models tend to keep it simple on the backend. They generally have simple database schema design and minimal features.
Sign up to receive tutorials on React Native.
Storage for preserving data
Data storage and processing is the end goal of any mobile application. The data storage creation normally goes through a two-step process:
Create the database design
Link the design for data consistency
This process is performed afresh for every new mobile application that is developed by the organization. Thus, it also adds to the cost of development.
Overall, the development and maintenance of each of the above add to the cost of mobile application development and maintenance. Imagine reusing the complete backend and data storage design – wouldn’t it be a great saving? This is precisely what we will talk about in the next section.
3. Powering up your application with ButterCMS
A headless CMS engine like ButterCMS will provide you with a backend that can last extensively across different projects and scale up automatically. It is an API-First CMS and standard blogging platform to set up your company blog easy. ButterCMS provides you with push-button functionality that is designed to integrate right into your existing application, regardless of tech stack. It is a headless CMS tool that can integrate with any framework or language. The powerful interface helps you to customize every element of your website or blog without any trouble. Butter CMS offers to hybridize from traditional CMS boundaries and get away with custom coding in lines.
With ButterCMS, you will have things working in seconds. There’s nothing to host, so you don’t need to apply any upgrades, which help to improve security. Butter employs the advantage of Fastly for advanced caching and Amazon CDN to instantly deliver your content, including built-in with SEO features.
a. Understanding ButterCMS features
ButterCMS is a platform for building CMS-powered websites, blogs, dynamic pages, and more in any programming language. Let us have a brief overview of the features of ButterCMS before integrating it in your application:
The Version Control allows the project team to share the same source code repository and keep changes in sync between workstations.
Approval Process Control allows us to approve or reject the content before publishing.
Document Management can store and manage various information and documents in electronic format.
Rich Text Editor allows writing content directly with rich text formatting.
Multi-language Support multiple languages to support global customers.
Drag and Drop Editor lets you customize the elements like image, web form, tables, boxes, etc. by simple drag and drop interface.
Content Blocks allows editors to build and edit dynamic pages without any developing knowledge.
WYSIWYG Editor helps to edit in real-time while building the website using the software.
b. Integrating with your application
ButterCMS has an elaborate list of tutorials for almost every programming language, including React Native applications. The tutorials provide easy start guides for integrating ButterCMS into your application. ButterCMS has its own plugins and libraries to provide easy to use functions for getting the data.
Integrating a headless engine like ButterCMS not only gets you the benefit of a ready-to-use backend but also provides your team with a UI for entering data at any point of time. This UI is easy-to-use and responsive. This is a perfect fit for applications focused on publishing images, news, blog articles, stories, quotes and other content of this nature.
4. Benefits of opting the headless way
A headless CMS comes with a substantial dose of flexibility. It delivers all the content seamlessly through an API to any device, in any context. Choosing a headless CMS is similar. The backend provides the content to an Android or iOS mobile app, a virtual reality (VR) experience, a kiosk, or any other medium your business claims.
A headless CMS offers you the ability to innovate swiftly by tweaking your front-end without affecting the backend, which saves you time and resources.
Developer-friendly
The headless CMS offers a simple user interface for content editors. The web pages appear as content items and can be easily edited, added, or removed. The process of adding, approving, and publishing this content by the appropriate development team is easy and saves a lot of development costs.
Security & Scalability
The headless CMS offers high scalability and security due to dividing responsibilities of the authoring and delivery system. The authoring part is entirely hidden, and the delivery part is separately scaled, and not accessible due to company firewalls.
Future-Proofing
A headless CMS delivers content via a dynamic API, meaning the actual system for content managing is entirely separate from the front-end of the site. This indicates that there is full flexibility in terms of what framework and languages are used on the front-end. In the future, it will be notably easier to change the design of the site when needed.
Speed
This is a content-first approach to the entire project timeline, as it means that high-quality websites can be built in a brief span of time. A headless CMS provides a system to store and edit data quickly but with simple API to consume it and follow a specific way to publish the data.
Almost Zero Maintenance Costs
By decoupling your content from the frontend, time and money spent on re-designing your site is reduced. A headless CMS dramatically brings down the operational and technological costs for cross-platform projects. Paying for content management and/or maintenance on diverse platforms for mobile apps can be avoided.
5. Final Takeaway
Nowadays, A headless CMS is the norm but creating a headless blog is on the rise. ButterCMS is that alternative that allows development teams to add a CMS and blogging functionality into their own native codebases using the ButterCMS API reducing significant time and money in both the short and long term.
We hope this post added to your knowledge of opting for a headless content management system and understanding the need for it.
Looking to migrate your backend too? – Let our experts help you out.
As you begin to make use of React hooks in your applications, you’ll want to be certain the code you write is nothing short of solid. There’s nothing like shipping buggy code. One way to be certain your code is bug-free is to write tests. And testing React hooks is not much different from how React applications are tested in general.
In this tutorial, we will look at how to do that by making use of a to-do application built with hooks. We’ll cover writing of tests using Ezyme and React Testing Library, both of which are able to do just that. If you’re new to Enzyme, we actually posted about it a little while back showing how it can be used with Jest in React applications. It’s not a bad idea to check that as we dig into testing React hooks.
Here’s what we want to test
A pretty standard to-do component looks something like this:
import React, { useState, useRef } from "react";
const Todo = () => {
const [todos, setTodos] = useState([
{ id: 1, item: "Fix bugs" },
{ id: 2, item: "Take out the trash" }
]);
const todoRef = useRef();
const removeTodo = id => {
setTodos(todos.filter(todo => todo.id !== id));
};
const addTodo = data => {
let id = todos.length 1;
setTodos([
...todos,
{
id,
item: data
}
]);
};
const handleNewTodo = e => {
e.preventDefault();
const item = todoRef.current;
addTodo(item.value);
item.value = "";
};
return (
Add Todo
Lists
{!todos.length ? (
No task!
) : (
{todos.map(todo => {
return (
{todo.item}
);
})}
)}
);
};
export default Todo;
Testing with Enzyme
We need to install the packages before we can start testing. Time to fire up the terminal!
npm install --save-dev enzyme enzyme-adapter-16
Inside the src directory, create a file called setupTests.js. This is what we’ll use to configure Enzyme’s adapter.
import Enzyme from "enzyme";
import Adapter from "enzyme-adapter-react-16";
Enzyme.configure({ adapter: new Adapter() });
Now we can start writing our tests! We want to test four things:
That the component renders
That the initial to-dos get displayed when it renders
That we can create a new to-do and get back three others
That we can delete one of the initial to-dos and have only one to-do left
In your src directory, create a folder called __tests__ and create the file where you’ll write your Todo component’s tests in it. Let’s call that file Todo.test.js.
With that done, we can import the packages we need and create a describe block where we’ll fill in our tests.
import React from "react";
import { shallow, mount } from "enzyme";
import Todo from "../Todo";
describe("Todo", () => {
// Tests will go here using `it` blocks
});
Test 1: The component renders
For this, we’ll make use of shallow render. Shallow rendering allows us to check if the render method of the component gets called — that’s what we want to confirm here because that’s the proof we need that the component renders.
it("renders", () => {
shallow();
});
Test 2: Initial to-dos get displayed
Here is where we’ll make use of the mount method, which allows us to go deeper than what shallow gives us. That way, we can check the length of the to-do items.
We mount the component then we make use of find() and instance() methods to set the value of the input field. We assert that the value of the input field is set to “Fix failing test” before going further to simulate a click event, which should add the new item to the to-do list.
We finally assert that we have three items on the list and that the third item is equal to the one we created.
Test 4: We can delete one of the initial to-dos and have only one to-do left
it("removes an item", () => {
const wrapper = mount();
wrapper
.find("li button")
.first()
.simulate("click");
expect(wrapper.find("li")).toHaveLength(1);
expect(wrapper.find("li span").map(item => item.text())).toEqual([
"Take out the trash"
]);
});
In this scenario, we return the to-do with a simulated click event on the first item. It’s expected that this will call the removeTodo() method, which should delete the item that was clicked. Then we’re checking the numbers of items we have, and the value of the one that gets returned.
The source code for these four tests are here on GitHub for you to check out.
import React from "react";
import { render, fireEvent } from "@testing-library/react";
import Todo from "../Todo";
import "@testing-library/jest-dom/extend-expect";
test("Todo", () => {
// Tests go here
}
Test 1: The initial to-do renders
We’ll write our tests in a test block. The first test will look like this:
What’s happening here? We’re making use of getTestId to return the node of the element where data-testid matches the one that was passed to the method. That’s the
element in this case. Then, we’re checking that it has a total of two children (each child being a element inside the unordered list). This will pass as the initial to-do is equal to two.
Test 2: We can add a new to-do
We’re also making use of getTestById here to return the node that matches the argument we’re passing in.
We use getByTestId to return the input field and the ul element like we did before. To simulate a click event that adds a new to-do item, we’re using fireEvent.click() and passing in the getByText() method, which returns the node whose text matches the argument we passed. From there, we can then check to see the length of the to-dos by checking the length of the children array.
Test 3: We can delete a to-do
This will look a little like what we did a little earlier:
it("deletes a to-do", () => {
const { getAllByTestId, getByTestId } = render();
const todos = getByTestId("todos");
const deleteButton = getAllByTestId("delete-button");
const first = deleteButton[0];
fireEvent.click(first);
expect(todos.children.length).toBe(1);
});
We’re making use of getAllByTestId to return the nodes of the delete button. Since we only want to delete one item, we fire a click event on the first item in the collection, which should delete the first to-do. This should then make the length of todos children equal to one.
There are two lint rules to abide by when working with hooks:
Rule 1: Call hooks at the top level
…as opposed to inside conditionals, loops or nested functions.
// Don't do this!
if (Math.random() > 0.5) {
const [invalid, updateInvalid] = useState(false);
}
This goes against the first rule. According to the official documentation, React depends on the order in which hooks are called to associate state and the corresponding useState call. This code breaks the order as the hook will only be called if the conditions are true.
Rule 2: Call hooks from React functional components
Hooks are meant to be used in React functional components — not in React’s class component or a JavaScript function.
We’ve basically covered what not to do when it comes to linting. We can avoid these missteps with an npm package that specifically enforces these rules.
npm install eslint-plugin-react-hooks --save-dev
Here’s what we add to the package’s configuration file to make it do its thing:
If you are making use of Create React App, then you should know that the package supports the lint plugin out of the box as of v3.0.0.
Go forth and write solid React code!
React hooks are equally prone to error as anything else in your application and you’re gonna want to ensure that you use them well. As we just saw, there’s a couple of ways we can go about it. Whether you use Enzyme or You can either make use of enzyme or React Testing Library to write tests is totally up to you. Either way, try making use of linting as you go, and no doubt, you’ll be glad you did.
The best way to learn something is by doing. This tutorial will help you learn how to build your own todo list app with React hooks and TypeScript. Try this easy tutorial, build your own todo list app, and get better in JavaScript, React and TypeScript.
The goal for this tutorial is to build your own todo list app. About the app in general. This todo list app will have very simple interface and it will focus on the most important features, i.e. create, check off and delete todos. About code. You will use React and React hooks, mostly useState hook.
There will be one occasion where you will also use useRef hook. Since this todo list app will utilize React hooks for managing state there is no need to use class components. So, you will build this app only with functional components. When it comes to styling your todo list app, you will use external CSS stylesheets.
One last things. First every todo item will have a unique id. These ids will be generated when the todo item is created. You will use this id to mark the todo as complete or to remove it. To make this easier, while following good practices and avoiding using indexes, you will use shortid package.
Project setup
As the first thing let’s create the basic app for your todo list app. We can do this very fast with the help of create-react-app. You can use this package with npm init react-app react-hooks-todo-list-app-ts --typescript, npx create-react-app react-hooks-todo-list-app-ts --typescript or yarn create react-app react-hooks-todo-list-app-ts --typescript. If you don’t want to use TypeScript, omit the --typescript flag at the end of the command.
These commands will create starting template for your todo list app, with workflow setup and almost all necessary dependencies. There is one dependency you will need to install manually, the shortid and types for this package. So, use npm i shortid and npm i -D @types/shortid, yarn add shortid and yarn add -D @types/shortid or pnpm i shortid and pnpm i -D @types/shortid.
There are some assets, such as React logo, that came with the app template. You can remove it because you will not need it. A very simple version of your package.json should look similar to this:
As the last thing, below is the final structure of this todo list app project. You can use this as you work on this tutorial to orient yourself. With that, you are ready to start working on your todo list app.
The first thing to do is create interfaces for your todo list app. You will use them to define the shape of component props and the todo object, or to type them. If you decided to use pure JavaScript, instead of TypeScript, you can skip this step. You will need to create four interfaces.
One for todo (todo object), one for todo form one for todo list and one for todo item. The todo object will have three properties, id, text, isCompleted. The TodoForm props contain array of todo objects and handleTodoCreate method. The TodoList props will contain handleTodoUpdate, handleTodoRemove, handleTodoComplete and handleTodoBlur methods and array of todo objects.
The TodoItem props will contain handleTodoUpdate, handleTodoRemove, handleTodoComplete, handleTodoBlur and a single todo object.
The first component you will build will be todo item. When you add new todo on your todo list, this item component will represent it. This component will be composed of a couple of elements. First, there will be a div with span elements for checking off the todo. Unchecked item will contain empty span, styled into a transparent circle with border.
Checked off todo item will contain span with check mark HTML entity, inside a green circle. The wrapper div will have onClick handler to check/uncheck the todo. Next will be another div with input. You will use this input element to render the title, or the text, of the todo. This is the simplest way to make every todo item editable, through input elements.
You will pass the title be done through value attribute, from todo object passed through props. Aside to this, this input will have two handler methods, one for onBlur and one for onChange. The last element will be also a div, now with “x” entity/icon. You will use this element to remove the todo item.
This div will have one onClick handler. As all the previous data, and handler methods, this too will be passed thorough props.
If you use TypeScript, import the TodoItemInterface interface from interfaces.ts and to use it to type props of this component. After this, type the onChange handler on input element with React.ChangeEvent because we are attaching onChange handler to input element.
// Import dependencies
import * as React from 'react'
// Import interfaces
import { TodoItemInterface } from './../interfaces'
// TodoItem component
const TodoItem = (props: TodoItemInterface) => {
return (
The todo list will be the second component you will create. This component will be very simple. This component will accept handler methods for the TodoItem, you’ve just created, and array of todo objects through props. The component itself will contain one div as a wrapper element.
Inside this div will be a list, one ul element. Inside this element, you will use map() to iterate over the array of todo objects, and create one li element with one TodoItem component for every todo object. You will then pass the individually todo objects to the TodoItem component, along with handler methods.
For TypeScript, remember to import TodoListInterface interface and use it to type the props of the TodoList component.
// Import dependencies
import * as React from 'react'
// Import TodoItem
import TodoItem from './todo-item'
// Import interfaces
import { TodoListInterface } from './../interfaces'
// TodoList component
const TodoList = (props: TodoListInterface) => {
return (
{props.todos.map((todo) => (
))}
)
}
export default TodoList
Todo form component
The todo “form” will is the first component where you will use useState React hook. It is also here where you will use the useRef React hook. You will use the useState hook to store the text passed to the input element, text for the todo title before you will create new todo item.
You will use the useRef hook to store reference to this input. The way you create new todo is by pressing “Enter” key, while you type some text inside that input. So, when you press “Enter” key you will use this reference to reset the input, by setting the value to empty string. This input will also have two handler methods for onChange and onKeyPress.
These two handler methods will be handleInputChange and handleInputEnter. The first, for onChange, will update the form state when you write something into the input, some todo title/text. The second, for onKeyPress, will create new todo object and reset the input field when it detect pressing “Enter” key.
Do you remember the shortid package? It is here where you are going to use this dependency. Inside the handleInputEnter function, inside the new todo object, you will use shortid to generate unique id for every new todo. Don’t worry. This will be simple. All you need is to call generate() on shortid and your new id is ready.
Lastly, few things for TypeScript. First, import TodoInterface and TodoFormInterface interfaces. Then, use the TodoInterface interface to type the new todo object inside handleInputEnter, and TodoFormInterface interface to type the props of TodoForm. Then, type the useRef hook, using and set it to null.
After that, there are also two events. For the first one, you can type it with React.ChangeEvent because we are attaching onChange handler to input element. For the second, you can type it with React.KeyboardEvent because we are “listening” for key press.
// Import dependencies
import * as React from 'react'
import shortid from 'shortid'
// Import interfaces
import {TodoInterface, TodoFormInterface} from './../interfaces'
// Todo form component
const TodoForm = (props: TodoFormInterface) => {
// Create ref for form input
const inputRef = React.useRef(null)
// Create form state
const [formState, setFormState] = React.useState('')
// Handle todo input change
function handleInputChange(event: React.ChangeEvent) {
// Update form state with the text from input
setFormState(event.target.value)
}
// Handle 'Enter' in todo input
function handleInputEnter(event: React.KeyboardEvent) {
// Check for 'Enter' key
if (event.key === 'Enter') {
// Prepare new todo object
const newTodo: TodoInterface = {
id: shortid.generate(),
text: formState,
isCompleted: false
}
// Create new todo item
props.handleTodoCreate(newTodo)
// Reset the input field
if (inputRef && inputRef.current) {
inputRef.current.value = ''
}
}
}
return (
You are almost done. There is just one component you need to build. This is the main TodoListApp component. This component will implement methods for creating, updating, removing and completing your todos. This will be done via handleTodoCreate, handleTodoUpdate, handleTodoRemove and handleTodoComplete methods.
It is also this component where you will store all existing todos, using the useState React hook. So, let’s build this component, step by step.
Imports
First, as usually, you will need to import dependencies for react. Now, you will also need to import render method from react-dom. This is because you will render the TodoListApp component, your todo list app, in the DOM.
You will also import TodoForm and TodoList components so you can later return, and render, them. When you import these components you should also import the main external CSS stylesheet, so you can later style your todo list app.
For TypeScript, you will need to import the TodoInterface interface. You will use this interface a couple of times, to type todos state and some method parameters.
// Import dependencies
import * as React from 'react'
import { render } from 'react-dom'
// Import components
import TodoForm from './components/todo-form'
import TodoList from './components/todo-list'
// Import interfaces
import { TodoInterface } from './interfaces'
// Import styles
import './styles/styles.css'
Creating todo list app state
The state fo your todo list app will be simple. It will be an array of objects. One object will represent one existing todo. In the beginning, you will initialize the todos state as an empty array.
For TypeScript, make sure to use the TodoInterface interface along with []. This will tell TypeScript you are “talking” about an array of todos objects, not just one todo object.
The first method for your todo list app will be method to create new todos, handleTodoCreate method. This method will accept one parameter, a todo object. The way it will work is simple. First, it will create new todo list app state, the newTodosState, by copying the current todo list app state.
Next, it will take the todo object, you pass as parameter when you call this method, and add that todo to the new todo list app state, the newTodosState, using push() method. After that, it will update the todo list app state, using setTodos() method.
About TypeScript. You will use the TodoInterface interface to type the todo parameter. You will also use this interface to type the newTodosState variable. In this case, you will again have specify you want an array of todo objects, adding [] after the TodoInterface.
// ....
// Creating new todo item
function handleTodoCreate(todo: TodoInterface) {
// Prepare new todos state
const newTodosState: TodoInterface[] = [...todos]
// Update new todos state
newTodosState.push(todo)
// Update todos state
setTodos(newTodosState)
}
// ....
Updating existing todos
Next, you will need method to update existing todos, handleTodoUpdate method. This method will accept two parameters, event and id. The id will be unique id generated for every todo item/object. Similarly to handleTodoCreate, this method will also start by creating new todo list app state, newTodosState, by copying the current todo list app state.
Next, it will use find() method to iterate over the newTodosState variable and find the correct todo item to update, using the id passed as argument. When it finds the correct todo item/object, it will change the value of its text key. New value will come from the value of the input inside specific todo item.
The last step is updating the todo list app state, using newTodosState and setTodos() method.
For TypeScript, use the TodoInterface interface to type the todo parameter passed to find() method. Use it also for the newTodosState variable, along with [] after the TodoInterface. Lastly, type the id parameter as a string.
// ....
// Update existing todo item
function handleTodoUpdate(event: React.ChangeEvent, id: string) {
// Prepare new todos state
const newTodosState: TodoInterface[] = [...todos]
// Find correct todo item to update
newTodosState.find((todo: TodoInterface) => todo.id === id)!.text = event.target.value
// Update todos state
setTodos(newTodosState)
}
// ....
Removing existing todos
Removing todos will be done using filter() method. First, you will create new todo list app state, newTodosState, by copying the current todo list app state. During this, you will use the filter() method to remove the todo you want to remove. This will be done by comparing id of all todos with the id of todo you want to remove.
When this is done, you will use this new, filtered, state to update the todos state with the setTodos() method.
For TypeScript, use the TodoInterface interface to type the todo parameter passed to filter() method. Then, use it also for the newTodosState variable, along with [] after the TodoInterface. Finally, type the id parameter as a string.
// ....
// Remove existing todo item
function handleTodoRemove(id: string) {
// Prepare new todos state
const newTodosState: TodoInterface[] = todos.filter((todo: TodoInterface) => todo.id !== id)
// Update todos state
setTodos(newTodosState)
}
// ....
Completing todos
The method for completing todos will look very similar to handleTodoUpdate method. First, it will copy the current todo list app state and store it in newTodosState variable. Then, it will use find() method to find specific todo item/object in todos state.
This time, it will negate the value of isCompleted key of the specific todo item/object. After this, it will use the setTodos method to update todos state.
Now, about TypeScript. First, use the TodoInterface interface to type the todo parameter passed to find() method. Next, use this interface also for the newTodosState variable, again with [] after the TodoInterface. The last type will be for the id. This will be a string.
// ....
// Check existing todo item as completed
function handleTodoComplete(id: string) {
// Copy current todos state
const newTodosState: TodoInterface[] = [...todos]
// Find the correct todo item and update its 'isCompleted' key
newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted = !newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted
// Update todos state
setTodos(newTodosState)
}
// ....
Ensuring every todo has title
The last thing. When you edit existing todo there should be some warning if you leave the text/title empty. To get this done you can watch change on input element inside every todo. Then, you can check its value is not an empty string, the length of the value is bigger than “0”.
If there is an empty string, you will add specific CSS class. When you input some text, you will remove that CSS class. This CSS class will mark the input with red border. You will define this class in your CSS stylesheet later.
As usually, the TypeScript. This will be quick. All there is to type is the event passed as parameter. Since you are attaching a onChange event handler on input element, you can use React.ChangeEvent.
// ....
// Check if todo item has title
function handleTodoBlur(event: React.ChangeEvent) {
if (event.target.value.length === 0) {
event.target.classList.add('todo-input-error')
} else {
event.target.classList.remove('todo-input-error')
}
}
// ....
Returning all components
Your todo list app is almost finished. Now, you now need to take all the components you’ve built so far, and imported in component, and return them. Make sure to provide all components with necessary props. After that, you can use the render() method and render the TodoListApp in the DOM.
// ...
return (
{/* Todo form component */}
{/* Todo list component */}
)
}
// Render the App in the DOM
const rootElement = document.getElementById('root')
render(, rootElement)
Putting it all together
You wrote a lot code in this main component. Let’s put it all together to make it more clear.
// Import dependencies
import * as React from 'react'
import { render } from 'react-dom'
// Import components
import TodoForm from './components/todo-form'
import TodoList from './components/todo-list'
// Import interfaces
import { TodoInterface } from './interfaces'
// Import styles
import './styles/styles.css'
// TodoListApp component
const TodoListApp = () => {
const [todos, setTodos] = React.useState([])
// Creating new todo item
function handleTodoCreate(todo: TodoInterface) {
// Prepare new todos state
const newTodosState: TodoInterface[] = [...todos]
// Update new todos state
newTodosState.push(todo)
// Update todos state
setTodos(newTodosState)
}
// Update existing todo item
function handleTodoUpdate(event: React.ChangeEvent, id: string) {
// Prepare new todos state
const newTodosState: TodoInterface[] = [...todos]
// Find correct todo item to update
newTodosState.find((todo: TodoInterface) => todo.id === id)!.text = event.target.value
// Update todos state
setTodos(newTodosState)
}
// Remove existing todo item
function handleTodoRemove(id: string) {
// Prepare new todos state
const newTodosState: TodoInterface[] = todos.filter((todo: TodoInterface) => todo.id !== id)
// Update todos state
setTodos(newTodosState)
}
// Check existing todo item as completed
function handleTodoComplete(id: string) {
// Copy current todos state
const newTodosState: TodoInterface[] = [...todos]
// Find the correct todo item and update its 'isCompleted' key
newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted = !newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted
// Update todos state
setTodos(newTodosState)
}
// Check if todo item has title
function handleTodoBlur(event: React.ChangeEvent) {
if (event.target.value.length === 0) {
event.target.classList.add('todo-input-error')
} else {
event.target.classList.remove('todo-input-error')
}
}
return (
Your todo list app is ready to go. Well, almost. There is a lot of space for some styling. Here are some styles you can use to make your todo list app look better.
Conclusion: How to Build a Todo List App with React Hooks and TypeScript
Congratulations, you’ve just built your own todo list app using React hooks and TypeScript! However, you don’t have to stop here. So, go ahead. Take this todo list app and make it better. Think about what features you would like it to have. Then, don’t wait for anything. Try to implement them by yourself. Have fun!
If you liked this article, then please consider subscribing.
I was starting to get a bit worried. The last few minor point releases of React had come out months apart and we were already into Q3 without a new release. My fears have been quelled though as React v16.9 is finally here with a few new features, bug fixes and deprecations!
The deprecations
I’m a “start with the bad news” type of guy, so let’s start by talking about the deprecations that were included in React v16.9 which will help us better prepare for v17 (and other future versions) down the road.
No more javascript: URLs
URLs that begin with javascript: have long been considered dangerous because of the potential of malicious data making it into your application:
constuserProfile={// Whoops, forgot to ensure this use input was /actually/ a URLwebsiteUrl:'javascript: alert("Remember little bobby tables?")';}<ahref={userProfile.websiteUrl}>MyWebsite</a>
Obviously it wouldn’t be good if your users could inject JavaScript right into your running application.
As mentioned, this is simply a deprecation in v16.9 and will only log a warning. You could go out of your way to circumvent this entirely by using dangerouslySetInnerHTML but you’d still be asking for trouble.
In a future major version (not necessarily v17) this will be converted from a warning to an error. I’d say it’s best to just stop using it all together so you can save the trouble in the future.
No more “factory” components
A feature I can file in the “TIL” category, is that React had support for a “factory” component.
For those unfamiliar, the factory pattern is when you have a creator class handles creating new classes for you rather than instantiating them directly. This is great in scenarios where you are dynamically generating class names and such.
In React, this means you can have a component that returns an object with it’s own render method. It also has a pretty nasty syntax that looks an awful lot like a function component:
As mentioned, this was news to me, and evidently not that widely used of a feature as the React Team mentioned that this is rarely used and probably won’t affect the majority of modern code bases.
If you do attempt to use it, you will receive a warning. There’s also a work around, but you’re better off converting it to a function of class component instead of trying to stay set in your ways.
Unsafe lifecycle methods renamed
The React Team gave us a head’s up over a year ago that the lifecycle methods that were considered unsafe would be renamed in a future 16.x release and the old names removed completely from the 17.x series.
The methods in question are as follows:
componentWillMount renamed to UNSAFE_componentWillMount
componentWillReceiveProps renamed to UNSAFE_componentWillReceiveProps
componentWillUpdate renamed to UNSAFE_componentWillUpdate
Never fear though, the old names will still work in React v16.9 but will throw a helpful warning to urge you to refactor your code or move to the new UNSAFE_ naming.
The purpose of the UNSAFE_ naming convention is to make it easier for us developers to identify potentially problematic code when doing reviews and such.
To ease migration efforts, there is a “codemod” script that can update your entire project to the new UNSAFE_ naming convention:
$ npx react-codemod rename-unsafe-lifecycles
The features
While not necessarily a let down of a release, this particular React release is a bit light on new features. One man’s opinion though 🙂
Measuring performance with
You may remember back in React v16.5 when the React Profiler was added to the React DevTools. This is great for a lot of smaller applications, but for a larger application, you probably want a more programmatic way to gather metrics.
The solution to this comes in the way of the component which you can be used to wrap components to help gain insight to the rendering “cost” of your application.
The new component requires an id property as well as an onRender property which will fire every time a component within the tree updates and triggers a re-render:
The onRender callback will receive information about which component re-rendered, how long it took, and other valuable information. You can read more about the profiler here.
Also, the profiler is automatically disabled in production, so there’s no additional logic to implement to make sure you don’t accidentally deploy with the profiler turned on. (C’mon, we’ve all done it 😉
Asynchronous ReactTestUtils.act()
React v16.8 introduced the act() utility to help with testing your application as if it were being run in a web browser.
While extremely useful, the act() utility was synchronous with no easy way to get it work in a more asynchronous fashion. This may have resulted in some sporadic warnings in your logs which couldn’t be easily fixed. Quite the bummer.
Fortunately, the React Team has improved the act() utility in React v16.9 so it can function asynchronously!
The Rest
A release of React is never complete without some notable bug fixes:
Fix for a memory leak caused by deleted subtrees being retained.
Better handling of infinite loops caused by setState inside of useEffect.
Fix for a crash in when findDOMNode() is called.
Ready to start using React v16.9?
React v16.9 is ready for your hacking pleasure, all you need to do is install it via your favorite package manager:
# Via npm$ npm install--save react@^16.9.0 react-dom@^16.9.0
# Via Yarn$ yarn add react@^16.9.0 react-dom@^16.9.0
You’re probably used to fetching data in React using axios or fetch. The usual method of handling data fetching is to:
Make the API call.
Update state using the response if all goes as planned.
Or, in cases where errors are encountered, an error message is displayed to the user.
There will always be delays when handling requests over the network. That’s just part of the deal when it comes to making a request and waiting for a response. That’s why we often make use of a loading spinner to show the user that the expected response is loading.
All these can be done using a library called React Async.
React Async is a promised-based library that makes it possible for you to fetch data in your React application. Let’s look at various examples using components, hooks and helpers to see how we can implement loading states when making requests.
For this tutorial, we will be making use of Create React App. You can create a project by running:
npx create-react-app react-async-demo
When that is done, run the command to install React Async in your project, using yarn or npm:
The library allows us to make use of directly in our JSX. As such, the component example will look like this;
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import Async from 'react-async';
// We'll request user data from this API
const loadUsers = () =>
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our component
function App() {
return (
{({ data, err, isLoading }) => {
if (isLoading) return "Loading..."
if (err) return `Something went wrong: ${err.message}`
if (data)
return (
React Async - Random Users
{data.map(user=> (
{user.name}
{user.email}
))}
)
}}
);
}
export default App;
First, we created a function called loadUsers. This will make the API call using the fetch API. And, when it does, it returns a promise which gets resolved. After that, the needed props are made available to the component.
The props are:
isLoading: This handles cases where the response has not be received from the server yet.
err: For cases when an error is encountered. You can also rename this to error.
data: This is the expected data obtained from the server.
As you can see from the example, we return something to be displayed to the user dependent on the prop.
Example 2: Loaders in hooks
If you are a fan of hooks (as you should), there is a hook option available when working with React Async. Here’s how that looks:
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import { useAsync } from 'react-async';
// Then we'll fetch user data from this API
const loadUsers = async () =>
await fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our component
function App() {
const { data, error, isLoading } = useAsync({ promiseFn: loadUsers })
if (isLoading) return "Loading..."
if (error) return `Something went wrong: ${error.message}`
if (data)
// The rendered component
return (
React Async - Random Users
{data.map(user=> (
{user.name}
{user.email}
))}
);
}
export default App;
This looks similar to the component example, but in this scenario, we’re making use of useAsync and not the Async component. The response returns a promise which gets resolved, and we also have access to similar props like we did in the last example, with which we can then return to the rendered UI.
Example 3: Loaders in helpers
Helper components come in handy in making our code clear and readable. These helpers can be used when working with an useAsync hook or with an Async component, both of which we just looked at. Here is an example of using the helpers with the Async component.
// Let's import React, our styles and React Async
import React from 'react';
import './App.css';
import Async from 'react-async';
// This is the API we'll use to request user data
const loadUsers = () =>
fetch("https://jsonplaceholder.typicode.com/users")
.then(res => (res.ok ? res : Promise.reject(res)))
.then(res => res.json())
// Our App component
function App() {
return (
Loading...
{data => {
return (
React Async - Random Users
{data.map(user=> (
{user.name}
{user.email}
))}
)
}}
{error => `Something went wrong: ${error.message}`}
);
}
export default App;
This looks similar to when we were making use of props. With that done, you could break the different section of the app into tiny components.
Conclusion
If you have been growing weary of going the route I mentioned in the opening section of this tutorial, you can start making of React Async in that project you are working on. The source code used in this tutorial can be found in their different branches on GitHub.