Book Image

React 17 Design Patterns and Best Practices - Third Edition

By : Carlos Santana Roldán
2 (1)
Book Image

React 17 Design Patterns and Best Practices - Third Edition

2 (1)
By: Carlos Santana Roldán

Overview of this book

Filled with useful React patterns that you can use in your projects straight away, this book will help you save time and build better web applications with ease. React 17 Design Patterns and Best Practices is a hands-on guide for those who want to take their coding skills to a new level. You’ll spend most of your time working your way through the principles of writing maintainable and clean code, but you’ll also gain a deeper insight into the inner workings of React. As you progress through the chapters, you’ll learn how to build components that are reusable across the application, how to structure applications, and create forms that actually work. Then you’ll build on your knowledge by exploring how to style React components and optimize them to make applications faster and more responsive. Once you’ve mastered the rest, you’ll learn how to write tests effectively and how to contribute to React and its ecosystem. By the end of this book, you'll be able to avoid the process of trial and error and developmental headaches. Instead, you’ll be able to use your new skills to efficiently build and deploy real-world React web applications you can be proud of.
Table of Contents (21 chapters)
1
Hello React!
4
How React Works
10
Performance, Improvements, and Production!
19
About Packt

Introducing TypeScript

TypeScript is a typed superset of JavaScript that is compiled to JavaScript, which means TypeScript is JavaScript with some additional features. TypeScript was designed by Anders Hejlsberg (the designer of C#) at Microsoft and is open source.

Let's see what the features of TypeScript are and how to convert JavaScript to TypeScript.

TypeScript features

This section will try to summarize the most important features you should be taking advantage of:

  • TypeScript is JavaScript: Any JavaScript code you write will work with TypeScript, which means if you already know how to use JavaScript basically you have all you need to do TypeScript; you just need to learn how to add types to your code. All the TypeScript code is transformed into JavaScript at the end.
  • JavaScript is TypeScript: This just means that you can rename any valid .js file with the .ts extension, and it will work.
  • Error checking: TypeScript compiles the code and checks for errors, which helps a lot to highlight errors before we run our code.
  • Strong typing: By default, JavaScript is not strongly typed. With TypeScript, you can add types to all your variables and functions, and you can even specify the returned value types.
  • Object-oriented programming supported: It supports concepts such as classes, interfaces, inheritance, and so on.

Converting JavaScript code into TypeScript

In this section, we will see how to transform some JavaScript code into TypeScript.

Let's suppose we have to check whether a word is a palindrome. The JavaScript code for this algorithm will be as follows:

function isPalindrome(word) {
const lowerCaseWord = word.toLowerCase()
const reversedWord = lowerCaseWord.split('').reverse().join('')

return lowerCaseWord === reversedWord
}

You can name this file palindrome.ts.

As you can see, we are receiving a string variable (word), and we are returning a boolean value, so how will this be translated to TypeScript?

function isPalindrome(word: string): boolean {
const lowerCaseWord = word.toLowerCase()
const reversedWord = lowerCaseWord.split('').reverse().join('')

return lowerCaseWord === reversedWord
}

You're probably thinking great, I just specified the string type as word and boolean type to the function returned value, but now what?

If you try to run the function with some value that is different from a string, you will get a TypeScript error:

console.log(isPalindrome('Level')) // true
console.log(isPalindrome('Anna')) // true
console.log(isPalindrome('Carlos')) // false
console.log(isPalindrome(101)) // TS Error
console.log(isPalindrome(true)) // TS Error
console.log(isPalindrome(false)) // TS Error

So, if you try to pass a number to the function, you will get the following error:

That's why TypeScript is very useful because it will force you to be more strict and explicit with your code.

Types

In the last example, we saw how to specify some primitive types for our function parameter and returned value, but you're probably wondering how you can describe an object or array with more details. Types can help us to describe our objects or arrays in a better way. For example, let's suppose you want to describe a User type to save the information into the database:

type User = {
username: string
email: string
name: string
age: number
website: string
active: boolean
}

const user: User = {
username: 'czantany',
email: '[email protected]',
name: 'Carlos Santana',
age: 33,
website: 'http://www.js.education',
active: true
}

// Let's suppose you will insert this data using Sequelize...
models.User.create({ ...user }}

We get the following error if you forget to add one of the nodes or put an invalid value in one of them:

If you need optional nodes, you can always put a ? next to the name of the node, as shown in the following code block:

type User = {
username: string
email: string
name: string
age?: number
website: string
active: boolean
}
You can name type as you want, but a good practice to follow is to add a prefix of T, so, for example, the User type will become TUser. In this way, you can quickly recognize that it is type and you don't get confused thinking it is a class or a React component.

Interfaces

Interfaces are very similar to types and sometimes developers don't know the differences between them. Interfaces can be used to describe the shape of an object or function signature just like types, but the syntax is different:

interface User {
username: string
email: string
name: string
age?: number
website: string
active: boolean
}
You can name an interface as you want, but a good practice to follow is to add a prefix of I, so, for example, the User interface will become IUser. In this way, you can quickly recognize that it is an interface and you don't get confused thinking it is a class or a React component.

An interface can also be extended, implemented, and merged.

Extending

An interface or type can also be extended, but again the syntax will differ, as shown in the following code block:

// Extending an interface
interface IWork {
company: string
position: string
}

interface IPerson extends IWork {
name: string
age: number
}

// Extending a type
type TWork = {
company: string
position: string
}

type TPerson = TWork & {
name: string
age: number
}

// Extending an interface into a type
interface
IWork {
company: string
position: string
}

type TPerson = IWork & {
name: string
age: number
}

As you can see, by using the & character, you can extend a type, while you extend an interface using the extends keyword.

Implementing

A class can implement an interface or type alias in the same exact way. But it cannot implement (or extend) a type alias that names a union type, for example:

// Implementing an interface
interface IWork {
company: string
position: string
}

class Person implements IWork {
name: 'Carlos'
age: 33
}

// Implementing a type
type TWork = {
company: string
position: string
}

class Person2 implements TWork {
name: 'Cristina'
age: 32
}

// You can't implement a union type
type TWork2 =
{ company: string; position: string } | { name: string; age: number }

class
Person3 implements TWork2 {
company: 'Google'
position: 'Senior Software Engineer'
}

If you write that code, you will get the following error in your editor:

As you can see, you are not able to implement a union type.

Declaration merging

Unlike a type, an interface can be defined multiple times and will be treated as a single interface (all declarations will be merged), as shown in the following code block:

interface IUser {
username: string
email: string
name: string
age?: number
website: string
active: boolean
}

interface IUser {
country: string
}

const user: IUser = {
username: 'czantany',
email: '[email protected]',
name: 'Carlos Santana',
country: 'Mexico',
age: 33,
website: 'http://www.js.education',
active: true
}

This is very useful when you need to extend your interfaces in different scenarios by just re-defining the same interface.