Abdu Taviq

React

YouTube Video

Advanced React Course with Typescript, React Router, React SSR and Clean Frontend Architecture youtube thumbnail
Advanced React Course with Typescript, React Router, React SSR and Clean Frontend Architecture youtube thumbnail

Tooling

1npm install -g create-react-app
2npx create-react-app todo --template typescript

Note: Please don’t use create-react-app for production projects

Project Commands

Summary

Components Types

Features

Internal State

1export const TodoContainer = (props: TodoContainerProps) => {
2  const [todos, setTodos] = useState<Todo[]>([]);
3  ("...");
4};

Computed State

They are computed from the internal state. When using useMemo & useCallback hook, the function is only called when the dependencies change. They are useful when you want to avoid re-rendering the child component when the internal state of the parent changes.

1export const TodoContainer = (props: TodoContainerProps) => {
2  "...";
3  const undoneTodos = useMemo(() => todos.filter((todo) => !todo.done), [todos]);
4  ("...");
5};
 1export const TodoContainer = (props: TodoContainerProps) => {
 2  "...";
 3  const addTodo = useCallback(
 4    (todo: Todo) => {
 5      setTodos([...todos, todo]);
 6    },
 7    [todos],
 8  );
 9  ("...");
10};

Components that use the useMemo & useCallback hook are called Memoized Components. They are useful when you want to avoid re-rendering the child component when the internal state of the parent changes. To avoid re-rendering the child component, you can use React.memo or React.PureComponent.

Shared State

1export const TodoContainer = (props: TodoContainerProps) => {
2  "...";
3  const { todos, setTodos } = useContext(TodoContext);
4  ("...");
5};

Props

 1export const TodoContainer = (props: TodoContainerProps) => {
 2  "...";
 3  return (
 4    <div className="todo-container">
 5      <TodoForm addTodo={props.addTodo} />
 6      <TodoList todos={props.todos} />
 7      <TodoStats todos={props.todos} />
 8    </div>
 9  );
10};

Events

1export const TodoContainer = (props: TodoContainerProps) => {
2  "...";
3  return (
4    <div className="todo-container">
5      <TodoList onToggleTodo={props.onToggleTodo} />
6    </div>
7  );
8};

Side Effects

1export const TodoContainer = (props: TodoContainerProps) => {
2  "...";
3  useEffect(() => {
4    props.loadTodos();
5
6    return cleanUpMethod;
7  }, []);
8  ("...");
9};

useEffect run twice when using React.StrictMode as a way to protect against unpredicted or bad side effects. This to make sure you call the clean-up function for example and make sure the components are always predictable.

Change Detection

Reactivity in React is made possible through the use of a virtual DOM (Document Object Model). The virtual DOM is a lightweight in-memory representation of the actual DOM that is used to calculate the changes that need to be made to the actual DOM in order to update the UI. When the state or props of a component change, the virtual DOM is updated to reflect the new data. Then, the virtual DOM calculates the differences between the current virtual DOM workInProgress and the previous virtual DOM, and applies those changes to the actual DOM in an efficient manner.

This happens in two phases:

  1. render phase - React creates the new Virtual DOM
  2. commit phase - React updates the DOM

React changes detection is called reconciliation. It is a process of comparing two trees and figuring out the minimum. The reconciliation is done in chunks. This is to avoid blocking the main thread.

Two methods are used to queue the changes:

The old reconciliation algorithm is called Stack Reconciliation. The new one is called Fiber Reconciliation.

Patterns

Component

They hold the visual representation of the data. They are stateless and receive data via props.

1export const TodoItem: React.FC<TodoContainerProps> = (props) => {
2  "...";
3};

Container

They hold the state and logic of the application. They are stateful and receive data via props.

1export const TodoContainer: React.FC<TodoContainerProps> = (props) => {
2  "...";
3};

HoC

They are functions that take a component as an argument and return a new component.

1export const withTodoContainer = (Component: ComponentType<typeof Component>) => {
2  "...";
3
4  return (props: TodoContainerProps) => {
5    "...";
6    return <Component {...props} {...containerProps} />;
7  };
8};

Service

They are functions that hold the business logic of the application. They are stateless and receive data via arguments. Famous examples are: API calls and State Management etc.

1export class TodoService {
2  public static addTodo = (todos: Todo[], todo: Todo): Todo[] => {
3    "...";
4  };
5}

Adapter

They allow us to use different implementations of the same interface. They are stateless and receive data via arguments.

1export class HttpAdapter {
2  public static get = (url: string): Promise<any> => {
3    "...";
4  };
5}

Store

They hold the state of the application. They are stateful and receive data via props.

Famous examples are: Redux, MobX, React Context etc.

1export class TodoStore {
2  public todos: Todo[] = [];
3
4  public addTodo = (todo: Todo): void => {
5    "...";
6  };
7}
8
9export const TodoContext = React.createContext(new TodoStore());

Important Libraries

react-router

Official routing system for react and support multiple features:

There are a couple of routers supported

There is also wouter which is a tiny router with a small bundle size.

Extra content