Redux

Redux

Redux is a predictable state container for JavaScript applications based on the Flux design pattern.

A Spotify Clone using React, NextJS and Redux

Spotify Clone using React, NextJS and Redux

This repository contains the source code of a Spotify clone
It's not an exact copy of the original Spotify but the main aspects are as close as possible copied to deliver the typical Spotify feeling. Check it out and let me know your thoughts. If you like it make sure to give it a ⭐ Star!

NOTE: The project is still in development and I will regularly make updates to the repo.

Demo

Use the link down below to check out the clone:

Demo

Tech Stack

Deployment

The deployment is done using Vercel.

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  images: {
    domains: ['i.scdn.co', 't.scdn.co', 'images.unsplash.com', 'charts-images.scdn.co']
  }
}

module.exports = nextConfig

package.json

{
  "name": "react-spotify",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@emotion/react": "^11.10.0",
    "@emotion/server": "^11.10.0",
    "@mantine/core": "^5.0.2",
    "@mantine/hooks": "^5.0.2",
    "@mantine/next": "^5.0.2",
    "@reduxjs/toolkit": "^1.8.3",
    "@types/lodash": "^4.14.182",
    "fast-average-color": "^7.1.0",
    "framer-motion": "^5.6.0",
    "lodash": "^4.17.21",
    "next": "12.2.3",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-redux": "^8.0.2",
    "sass": "^1.45.1",
    "tabler-icons-react": "^1.54.0"
  },
  "devDependencies": {
    "@types/node": "18.6.3",
    "@types/react": "18.0.15",
    "@types/react-dom": "18.0.6",
    "autoprefixer": "^10.4.8",
    "eslint": "8.20.0",
    "eslint-config-next": "12.2.3",
    "postcss": "^8.4.14",
    "tailwindcss": "^3.1.7",
    "typescript": "4.7.4"
  }
}

Download details:

Author: Gamekohl
Source code: https://github.com/Gamekohl/react-spotify
License: MIT license

#next #nextjs #react #javscript #redux

A Spotify Clone using React, NextJS and Redux
许 志强

许 志强

1659677040

如何构建基于 Redux 的 React 应用程序

我们正在解决的问题

在很多情况下,当我们想要创建一个小型应用程序时,我们可能会有一些组件声明并使用它们自己的状态。在少数情况下,组件可能希望与其直接子级共享状态。

我们可以通过在组件中本地声明状态来处理这些情况——如果需要,可能会以 props 的形式将状态传递给它的子组件(也称为 prop 钻取)。

但是,如果您的应用程序的大小增加,您可能需要将状态传递给可能在层次结构下几个步骤的子级。您可能还需要在兄弟组件之间使用公共状态。

当然,在兄弟组件之间共享状态的情况下,我们可以在它们的父组件中声明状态,然后通过 prop Drill 将状态传递给它们的子组件。但这可能并不总是可行的,并且有其自身的缺点,我们稍后会看到。

只需考虑下图:

49 组

这是典型 React 应用程序中组件文件结构的示意图。

假设我们需要在 Child 5 和 Child 6 之间共享一个公共状态。在这种情况下,我们可以很好地在它们的父级(即 Child 2)中声明一个状态并将状态传递给两个子级(5 和 6) .

目前一切都很好。但是如果我们需要在 Child 3 中拥有相同的状态呢?在这种情况下,我们需要在儿童 5、6 和 3 的共同父/祖父母中声明状态,即 App 组件。

同样,如果我们想在树中相距较远的 4、11 和 10 孩子之间共享一个状态怎么办?我们将再次需要在 App 组件中创建状态,然后进行多级道具钻探以将状态从 App 传递到这些组件。

随着时间的流逝和我们的应用程序大小的增长,它将开始使我们的应用程序组件或任何其他此类常见的父组件杂乱无章地声明不必要的状态。这些声明不是由这些组件直接使用,而是由它们的一些远低于子级使用。

多步支柱钻孔的缺点

多级螺旋钻主要有两个缺点。他们是:

  • 不必要的组件膨胀:如上所述,随着我们的应用程序大小的增长,一些常见的父组件可能会因不必要的状态声明而变得臃肿。并且这些组件可能不会直接使用这些声明,但它们可能会被它们的一些遥远的孩子使用。其他一些组件也可能会变得臃肿,它们只是充当子组件的道具传递者。这也会对代码的可读性产生负面影响。
  • 不必要的重新渲染:不必要的重新渲染对于客户端应用程序来说是一个很大的禁忌。不必要的重新渲染会使应用程序变慢、滞后、反应迟钝,并给用户带来糟糕的体验。在 React 中,重新渲染是由 state 或 prop 更改以及其他原因引起的。因此,如果一个组件实际上并没有使用状态,而只是充当道具从父级到子级的通道,那么当状态/道具发生变化时,它也可能会不必要地重新渲染。看下图更好理解

Group-52-1

这个问题的解决方案

这就是为什么我们使用像 Redux 或 MobX 这样的状态管理应用来以更统一和高效的方式处理上述状态管理场景的原因。

在像 Redux 这样的状态管理解决方案中,我们可以创建一个全局状态并将其放入存储中。无论哪个组件需要来自该商店的任何状态,都可以通过订阅该商店轻松获得它。这样我们就可以摆脱上述两个缺点。

  • 组件的整理:从“实际”使用它的组件中按需获取状态可以通过消除所有不必要的支柱钻孔,在很大程度上整理我们的许多组件。
  • 不再有不必​​要的重新渲染:由于我们没有仅充当道具传递器的组件,因此我们还避免了对这些组件进行不必要的重新渲染。当状态改变时,只有使用全局状态的组件才会重新渲染,这是一种期望的行为。

您将在这里学到什么

在本教程中,您将学习如何设置自己的基于 Redux 的 React 应用程序。我们将创建一个 react 应用程序并设置 redux 以能够全局管理状态,以便任何组件都可以访问状态的任何部分(因此名称为 redux 驱动的反应应用程序)。可以尝试的其他一些 redux 替代方案是 MobX、Zusand 等,但在本文中,我们将使用 redux。

我们将介绍如何创建商店并将其连接到应用程序。我们还将了解如何编写操作并在用户交互中分派它们。然后我们将看到如何制作 reducer 和更新 store,从 App 的其他子组件中读取 store,等等。

在此过程中,我还将提供所有重要的代码片段,以便您在阅读和编写代码时可以快速启动应用程序。

为了让您在开始时一目了然,这是我们最终将构建的内容:

finalAppDemo

我们将创建一个基本应用程序,我们可以在其中添加和删除购物车中的项目。我们将管理 Redux 存储中的状态更改并在 UI 中显示信息。

在我们开始之前

在继续本教程之前,您应该熟悉 Redux 存储、操作和减速器。

如果你不是,你可以阅读我在 Redux 上写的上一篇文章(如果你还没有的话):什么是 Redux?为初学者解释存储、操作和减速器

这将帮助您理解当前的文章。在之前的教程中,我试图解释 Redux 的基本原理/概念。我介绍了 store 是什么,actions 是什么,以及 reducer 是如何工作的。我还通过一个示例讨论了使 Redux 可预测的原因。

卑鄙的奴才

初始代码设置

让我们为我们的项目设置所需的一切。只需按照这些步骤操作,您就可以立即启动并运行。

1. 使用 create-react-app 命令创建一个 React 应用

npx create-react-app react-app-with-redux

2.进入新创建的文件夹

只需键入此命令即可导航到新文件夹:

cd react-app-with-redux

3. 安装 Redux 和 react-redux 库

你可以像这样安装 Redux 和 react-redux:

npm install redux react-redux

4. 运行应用程序

您可以使用以下命令运行您的新应用程序:

npm start

如何构建主应用程序

5.如何创建Reducer

要创建reducer,首先在srcnamed中创建一个文件夹actionTypes。然后在其中创建一个名为actionTypes.js. 该文件将包含应用程序将要处理的所有操作。

在 中添加以下行actionTypes.js

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

由于我们的应用程序将具有添加和删除项目的功能,因此我们需要上述两种操作类型。

接下来在被src调用的文件夹中创建一个文件夹,reducers并在其中创建一个名为cartReducer.js. 该文件将包含与购物车组件相关的所有减速器逻辑。

注意:我们将在第 8 步中创建视图/ UI,所以请稍等。

在 中添加以下行cartReducer.js

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

正如我们在之前的教程中讨论的那样,我们为应用程序创建了一个初始状态state,并将其分配给函数中的默认参数cartReducer

此函数打开调度的动作类型。然后根据与动作类型匹配的任何情况,它对状态进行必要的更改并返回更新状态的新实例。

如果没有任何动作类型匹配,则状态返回原样。

最后,我们对函数进行默认导出cakeReducer,以便在商店创建过程中使用它。

6.如何创建商店并提供给应用程序

在里面创建一个src带有名称的文件store.js并使用以下命令创建存储:

const store = createStore()

在 中添加以下行store.js

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

现在是时候将它提供storeApp组件了。为此,我们将使用从库中获得的<Provider>标签。react-redux

我们使用以下语法将整个App组件包装在标签内:<Provider>

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

App通过将组件包装在<Provider>标签内,所有的子组件App都可以访问store. 你可以阅读我之前关于什么是 Redux 的文章?为初学者解释存储、操作和减速器以了解更多信息。

继续,将以下行App.js添加到文件中:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. 创建动作

现在在里面创建一个src名为的文件夹,actions并在里面创建一个名为cartAction.js. 在这里,我们将添加要在某些用户交互上分派的所有操作。

在 中添加以下行cartAction.js

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

在上面的代码中,我们创建了两个动作创建器(返回action对象的纯 JS 函数),分别称为addItem()deleteItem()。两个动作创建者都返回action具有特定type.

注意:每个action对象都必须具有唯一的type值。除此之外,与操作对象一起传递的任何附加数据都是可选的,并且将取决于用于更新state

8. 如何创建视图/UI

现在我们已经创建了所有必需的实体,例如 store、actions 和 Reducers,是时候创建 UI 元素了。

在里面创建一个component文件夹src和一个Cart.js文件。在里面添加以下行Cart.js

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Cart在文件中添加这个组件App.js

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

为了使它有点像样,我添加了一些基本样式App.css如下:

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

这是 UI 现在的样子:

截图-2022-05-20-at-20.01.01

9. 如何使用useSelectorhook读取和访问 store

useSelectorreact-redux库提供的一个钩子,可以帮助我们阅读store它及其内容。

从中导入钩子react-redux并使用以下语法通过useSelector钩子读取存储:

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

添加useSelector钩子后,您的Cart.js文件将如下所示:

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

控制台记录状态将为我们提供我们在第 5 步中在 reducer 文件中设置的初始状态。

屏幕截图-2022-05-21-at-01.10.28

10. 如何使用useDispatch钩子在按钮单击时调度动作

react-redux 库为我们提供了另一个称为钩子的useDispatch钩子。它帮助我们调度动作或动作创建者,它们反过来又返回动作。语法如下:

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

因此,在我们的 will 中添加一个调度Cart.js程序最终使文件看起来像这样:

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

请注意单击“将商品添加到购物车”按钮时,我们是在第 1 步中创建dispatch的动作创建者addItem()。7.

类似地,点击Remove Item from Cart按钮,我们用deleteItem().

state变量存储应用程序的状态,它基本上是一个带有 key 的对象numOfItems。所以state.numOfItems给了我们商店中当前的项目数量。

我们在视图中显示这些信息<h2>Number of items in Cart: {state.numOfItems}</h2>

为了更深入地挖掘,当用户单击“将商品添加到购物车”按钮时,它会调度addItem()操作创建者。这反过来又返回一个action类型为 的对象type: ADD_ITEM

正如我之前的教程中提到的,当一个动作被调度时,所有的 reducer 都会被激活。

目前在这个例子中,我们只有一个减速器—— cartReducer. 所以它变得活跃并监听action调度。

如步骤 5 所示,reducer 将 state 和 action 作为输入,打开action type返回更新后的 state 的新实例

在这个例子中,当动作与type: ADD_ITEM第一个 switch case 匹配时,它首先使用扩展运算符复制整个状态...state。然后它进行必要的更新——在添加项目的情况下是numOfItems: state.numOfItems + 1(即增加numOfItems1)。

类似地,使用相同的逻辑,在单击“从购物车中移除商品”按钮时,将type: DELETE_ITEM调度一个带有 type 的操作,该操作会减少numOfItems1。

这是工作应用程序的演示:

finalAppDemo-1

请注意,我们如何能够根据numOfItemsRedux 存储中的值来控制 Remove Item from Cart 按钮的行为。由于负数的项目没有意义,我们禁用了从购物车中删除项目按钮如果state.numOfItems <= 0

这样我们就可以防止用户减少购物车中已经为 0 的商品数量。

这是一个基本示例,向您展示了我们如何根据应用程序的内部状态来控制各种 DOM 元素的行为。

你去吧!我们刚刚完成了我们的第一个 Redux 驱动的 React 应用程序的设置。现在,您可以继续根据您的要求创建各种其他组件,并在它们之间共享一个通用的全局状态。

GitHub 回购

这是该项目的 GitHub 存储库,因此您可以根据需要查看完整的源代码:GitHub 存储库

概括

在本文中,我们学习了如何快速启动基于 Redux 的 React 应用程序。

在此过程中,我们学会了如何:

  • 创建动作、动作创建者、reducers 和 store
  • 将商店提供给应用程序使用<Provider>
  • 使用钩子从组件中读取/访问存储useSelector并在 UI 中显示状态信息
  • useDispatch使用钩子调度用户事件的动作,例如按钮点击
  • 使用基于应用程序状态的逻辑控制 DOM 元素的行为
  • 我们了解了低效状态管理和多级螺旋钻的缺点

 来源:https ://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

如何构建基于 Redux 的 React 应用程序

Cómo Construir Una Aplicación React Impulsada Por Redux

El problema que estamos resolviendo

En muchos casos, cuando queremos crear una aplicación pequeña, es posible que tengamos algunos componentes que declaren y usen su propio estado. Y en algunos casos, un componente podría querer compartir el estado con sus hijos inmediatos.

Podemos manejar estas situaciones simplemente declarando estados localmente dentro de un componente, y tal vez pasar el estado a sus elementos secundarios en forma de accesorios si es necesario (lo que también se conoce como perforación de accesorios).

Pero si su aplicación crece en tamaño, es posible que deba pasar el estado a un elemento secundario, que podría estar varios pasos por debajo de la jerarquía. Es posible que también deba usar un estado común entre los componentes hermanos.

Claro, en el caso de compartir el estado entre componentes hermanos, podemos declarar el estado en sus padres y luego pasar el estado a sus hijos mediante la perforación de puntales. Pero eso puede no ser siempre factible y tiene sus propias desventajas que veremos en un momento.

Basta con considerar el siguiente diagrama:

Grupo-49

Esta es una representación esquemática de una estructura de archivos de componentes en una aplicación típica de React.

Digamos que necesitamos compartir un estado común entre Child 5 y Child 6. En ese caso, podemos muy bien declarar un estado en su padre (es decir, Child 2) y pasar el estado a los dos hijos (5 y 6) .

Todo bien a partir de ahora. Pero, ¿y si necesitamos tener el mismo estado en Child 3? En ese caso, necesitaríamos declarar el estado en el padre/abuelo común de los niños 5, 6 y 3, es decir, el componente de la aplicación.

Del mismo modo, ¿qué pasa si queremos compartir un estado entre los niños 4, 11 y 10 que están lejos uno del otro en el árbol? Tendríamos que volver a crear el estado en el componente de la aplicación y luego realizar varios niveles de exploración de accesorios para pasar el estado de la aplicación a estos componentes.

Y a medida que pasa el tiempo y nuestra aplicación crece en tamaño, comenzará a hacer que nuestro componente de la aplicación o cualquier otro componente principal común se llene de declaraciones de estado innecesarias. Estas declaraciones no son utilizadas directamente por estos componentes, pero son utilizadas por algunos de sus hijos más lejanos.

Desventajas de la perforación con puntal de varios pasos

Existen principalmente dos desventajas con la perforación con puntal de varios niveles. Están:

  • Inflación innecesaria de componentes: como se discutió anteriormente, a medida que nuestra aplicación crece en tamaño, algunos componentes principales comunes pueden inflarse con declaraciones de estado innecesarias. Y es posible que estos componentes no utilicen directamente esas declaraciones, pero podrían ser utilizados por algunos de sus hijos lejanos. Algunos otros componentes también pueden hincharse y solo actúan como transmisores de accesorios para un componente secundario. Esto también afectará negativamente la legibilidad del código.
  • Reprocesamiento innecesario: el reprocesamiento innecesario es un gran no para una aplicación del lado del cliente. Las repeticiones innecesarias pueden hacer que una aplicación sea lenta, lenta, que no responda y brinde una mala experiencia al usuario. En React, las re-renderizaciones son causadas por cambios de estado o prop, entre otras razones. Por lo tanto, si un componente en realidad no usa un estado y solo actúa como un pasaje de padre a hijo para los accesorios, entonces también podría volver a renderizarse innecesariamente cuando cambien el estado o los accesorios. Vea la imagen de abajo para entenderlo mejor

Grupo-52-1

La solución a este problema

Es por eso que usamos una aplicación de administración de estado como Redux o MobX para manejar los escenarios anteriores de administración de estado de una manera más uniforme y eficiente.

En este tipo de soluciones de gestión de estado como Redux, podemos crear un estado global y ponerlo en una tienda. Cualquiera que sea el componente que requiera cualquier estado de esa tienda, puede obtenerlo fácilmente suscribiéndose a la tienda. De esta manera podemos deshacernos de las dos desventajas anteriores.

  • Eliminación de componentes: obtener el estado a pedido del componente que "realmente" lo está utilizando puede eliminar muchos de nuestros componentes en gran medida al eliminar todas las perforaciones innecesarias.
  • No más renderizaciones innecesarias: como no tenemos componentes que solo actúen como transmisores, también evitamos la renderización innecesaria de esos componentes. Solo los componentes que usan una parte del estado global se vuelven a renderizar cuando el estado cambia, lo cual es un comportamiento deseado.

Lo que aprenderás aquí

En este tutorial, aprenderá cómo configurar su propia aplicación React impulsada por Redux. Crearemos una aplicación de reacción y configuraremos redux para poder administrar el estado globalmente, de modo que cualquier componente pueda acceder a cualquier parte del estado (de ahí el nombre de aplicación de reacción impulsada por redux). Algunas de las otras alternativas de redux que uno puede probar son MobX, Zustand, etc., pero para este artículo usaremos redux.

Veremos cómo crear la tienda y conectarla a la aplicación. También veremos cómo escribir acciones y distribuirlas en las interacciones del usuario. Luego veremos cómo hacer reductores y actualizar la tienda, leer la tienda de otros componentes que son hijos de la aplicación y mucho más.

También proporcionaré todos los fragmentos de código importantes en el camino para que pueda activar rápidamente la aplicación mientras lee y codifica.

Para darle un vistazo al principio, esto es lo que construiremos al final:

finalAppDemo

Estaremos creando una aplicación básica donde podemos agregar y eliminar artículos en un carrito. Administraremos los cambios de estado en la tienda Redux y mostraremos la información en la interfaz de usuario.

Antes que empecemos

Antes de continuar con este tutorial, debe estar familiarizado con la tienda, las acciones y los reductores de Redux.

Si no lo eres, puedes leer mi último artículo que escribí sobre Redux (si aún no lo has hecho): ¿Qué es Redux? Tienda, acciones y reductores explicados para principiantes .

Esto le ayudará a comprender el artículo actual. En este tutorial anterior, traté de explicar los principios/conceptos fundamentales de Redux. Cubrí qué es la tienda, qué son las acciones y cómo funcionan los reductores. También discuto lo que hace que Redux sea predecible junto con un ejemplo.

Despicable-me-minions

Configuración de código inicial

Vamos a configurar todo lo que necesitamos para nuestro proyecto. Simplemente siga estos pasos y estará listo y funcionando en muy poco tiempo.

1. Cree una aplicación React con el comando create-react-app

npx create-react-app react-app-with-redux

2. Ir a la carpeta recién creada

Simplemente escriba este comando para navegar a la nueva carpeta:

cd react-app-with-redux

3. Instale Redux y las bibliotecas react-redux

Puedes instalar Redux y reaccionar-redux así:

npm install redux react-redux

4. Ejecute la aplicación

Puede ejecutar su nueva aplicación con el siguiente comando:

npm start

Cómo construir la aplicación principal

5. Cómo crear el Reductor

Para crear un reductor, primero cree una carpeta dentro srcllamada actionTypes. Luego crea un archivo dentro de él llamado actionTypes.js. Este archivo contendrá todas las acciones que tratará la aplicación.

Agregue las siguientes líneas en actionTypes.js:

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

Dado que nuestra aplicación tendrá la funcionalidad de agregar y eliminar elementos, necesitamos los dos tipos de acción anteriores.

A continuación, cree una carpeta dentro de la srcllamada reducersy cree un nuevo archivo llamado cartReducer.js. Este archivo contendrá toda la lógica reductora relacionada con el componente del carrito .

Nota : Crearemos la vista/interfaz de usuario en el paso 8, así que espera.

Agregue las siguientes líneas en cartReducer.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

Como lo discutimos en mi tutorial anterior , creamos un estado inicial para la aplicación y lo asignamos al parámetro predeterminado de statela cartReducerfunción.

Esta función activa el tipo de acción enviada. Luego, según el caso que coincida con el tipo de acción, realiza los cambios necesarios en el estado y devuelve una nueva instancia nueva del estado actualizado.

Si ninguno de los tipos de acción coincide, el estado se devuelve tal cual.

Finalmente hacemos una exportación por defecto de la cakeReducerfunción para usarla en el proceso de creación de la tienda.

6. Cómo crear la tienda y proporcionarla a la aplicación

Cree un archivo dentro srccon el nombre store.jsy cree la tienda usando este comando:

const store = createStore()

Agregue las siguientes líneas en store.js:

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

Ahora es el momento de proporcionar esto storeal Appcomponente. Para esto usaremos la <Provider>etiqueta que obtenemos de la react-reduxbiblioteca.

Envolvemos todo el Appcomponente dentro de la <Provider>etiqueta usando la siguiente sintaxis:

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

Al envolver el Appcomponente dentro de la <Provider>etiqueta, todos los componentes Appsecundarios obtendrán acceso al archivo store. Puedes leer mi artículo anterior sobre ¿Qué es Redux? Tienda, acciones y reductores explicados para principiantes para saber más.

Continuando con App.js, agregue las siguientes líneas al archivo:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. Crea las Acciones

Ahora cree una carpeta dentro srcllamada actionsy cree un archivo dentro llamado cartAction.js. Aquí agregaremos todas las acciones que se enviarán en algunas interacciones del usuario.

Agregue las siguientes líneas en el cartAction.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

En el código anterior, creamos dos creadores de acciones (funciones JS puras que devuelven actionobjetos) llamados addItem()y deleteItem(). Ambos creadores de acciones devuelven actionobjetos con un type.

Nota : Cada actionobjeto debe tener un valor único type. Además, cualquier dato adicional pasado con el objeto de acción es opcional y dependerá de la lógica utilizada para actualizar elstate

8. Cómo crear la vista/IU

Ahora que hemos creado todas las entidades necesarias, como la tienda, las acciones y los reductores, es el momento de crear los elementos de la interfaz de usuario.

Cree una componentcarpeta dentro srcy un Cart.jsarchivo dentro de ella. Agregue las siguientes líneas dentro Cart.js:

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Agregue este Cartcomponente en el App.jsarchivo:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

Solo para hacerlo un poco presentable, he agregado un poco de estilo básico de la App.csssiguiente manera:

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

Así es como se ve la interfaz de usuario a partir de ahora:

Captura de pantalla-2022-05-20-a-20.01.01

9. Cómo leer y acceder a la tienda usando el useSelectorgancho

useSelectores un gancho proporcionado por la biblioteca react-redux que nos ayuda a leer el storey su(s) contenido(s).

Importe el gancho desde react-reduxy use la siguiente sintaxis para leer la tienda con useSelectorgancho:

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

Después de agregar el useSelectorgancho, su Cart.jsarchivo se verá así:

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

El registro del estado en la consola nos dará el estado inicial que configuramos en el archivo reducer en el paso 5.

Captura de pantalla-2022-05-21-a-01.10.28

10. Cómo enviar una acción al hacer clic en un botón con el useDispatchgancho

La biblioteca react-redux nos da otro gancho llamado useDispatchgancho. Nos ayuda a despachar las acciones o creadores de acciones que a su vez devuelven acciones. La sintaxis es la siguiente:

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

Por lo tanto, agregar un despachador a nuestro Cart.jsarchivo finalmente hará que se vea así:

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

Tenga en cuenta cómo al hacer clic en el botón Agregar artículo al carrito , dispatchel creador de la acción addItem()que creamos en el paso no. 7.

De manera similar, al hacer clic en el botón Eliminar artículo del carrito , enviamos al creador de la acción con deleteItem().

La statevariable almacena el estado de la aplicación, que es básicamente un objeto con una clave numOfItems. Entonces state.numOfItemsnos da el número actual de valor de artículos en la tienda.

Mostramos esta información en la vista en la línea <h2>Number of items in Cart: {state.numOfItems}</h2>.

Para profundizar un poco más, cuando un usuario hace clic en el botón Agregar artículo al carrito, envía al addItem()creador de la acción. Esto, a su vez, devuelve un actionobjeto de tipo type: ADD_ITEM.

Como mencioné en mi tutorial anterior , cuando se envía una acción, todos los reductores se activan.

Actualmente, en este ejemplo, solo tenemos un reductor: cartReducer. Entonces se activa y escucha a los actiondespachados.

Como se muestra en el paso 5, el reductor toma el estado y la acción como entrada, enciende action typey devuelve la nueva instancia del estado actualizado .

En este ejemplo, cuando la acción con type: ADD_ITEMcoincide con el primer caso de cambio, primero hace una copia de todo el estado usando el operador de extensión ...state. Luego realiza la actualización necesaria, que en el caso de agregar elementos es numOfItems: state.numOfItems + 1(es decir, aumenta numOfItemsen 1).

De manera similar, usando la misma lógica, al hacer clic en el botón Eliminar artículo del carrito, type: DELETE_ITEMse despacha una acción con tipo que va y disminuye numOfItemsen 1.

Aquí está la demostración de la aplicación de trabajo:

finalAppDemo-1

Observe cómo pudimos controlar el comportamiento del botón Eliminar artículo del carrito en función del valor de numOfItemsen la tienda Redux. Como un número negativo de artículos no tiene sentido, deshabilitamos el botón Eliminar artículo del carrito si state.numOfItems <= 0.

De esta manera, podemos evitar que el usuario disminuya la cantidad de artículos en el carrito si ya es 0.

Este fue un ejemplo básico para mostrarle cómo podemos controlar el comportamiento de varios elementos DOM en función del estado interno de la aplicación.

¡Y ahí lo tienes! Acabamos de terminar de configurar nuestra primera aplicación React impulsada por Redux. Ahora puede continuar y crear varios otros componentes según sus requisitos y compartir un estado global común entre ellos.

Repositorio de GitHub

Aquí está el repositorio de GitHub del proyecto para que pueda examinar el código fuente completo si lo desea: repositorio de GitHub

Resumen

En este artículo, aprendimos cómo activar rápidamente una aplicación React impulsada por Redux.

En el camino, aprendimos a:

  • Crear acciones, creadores de acciones, reductores y la tienda.
  • Proporcione la tienda a la aplicación usando<Provider>
  • Lea/acceda a la tienda desde los componentes usando el useSelectorgancho y muestre la información de estado en la interfaz de usuario
  • Distribuya las acciones en los eventos del usuario, como los clics en los botones, utilizando el useDispatchgancho
  • Controle el comportamiento de los elementos DOM con lógica basada en el estado de la aplicación
  • Aprendimos cuáles son las desventajas de una gestión estatal ineficiente y múltiples niveles de perforación de apoyo

 Fuente: https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

Cómo Construir Una Aplicación React Impulsada Por Redux
Iara  Simões

Iara Simões

1659639600

Como Construir Um Aplicativo React Alimentado Por Redux

O problema que estamos resolvendo

Em muitos casos, quando queremos criar um aplicativo pequeno, podemos ter alguns componentes que declaram e usam seu próprio estado. E em alguns casos, um componente pode querer compartilhar o estado com seus filhos imediatos.

Podemos lidar com essas situações apenas declarando estados localmente dentro de um componente – e talvez passar o estado para seus filhos na forma de props, se necessário (o que também é conhecido como prop drill).

Mas se o tamanho do seu aplicativo aumentar, talvez seja necessário passar o estado para um filho que pode estar várias etapas abaixo na hierarquia. Você também pode precisar usar um estado comum entre componentes irmãos.

Claro, no caso de compartilhamento de estado entre componentes irmãos, podemos declarar o estado em seus pais e, em seguida, passar o estado para seus filhos por perfuração de suporte. Mas isso nem sempre é viável e tem suas próprias desvantagens que veremos em breve.

Basta considerar o seguinte diagrama:

Grupo-49

Esta é uma representação esquemática de uma estrutura de arquivo de componente em uma aplicação React típica.

Digamos que precisamos compartilhar um estado comum entre o Filho 5 e o Filho 6. Nesse caso, podemos muito bem declarar um estado em seu pai (ou seja, Filho 2) e passar o estado para os dois filhos (5 e 6) .

Tudo bem a partir de agora. Mas e se precisarmos ter o mesmo pedaço de estado na Criança 3? Nesse caso, precisaríamos declarar o estado no pai/avô comum dos Filhos 5, 6 e 3 – ou seja, o componente App.

Da mesma forma, e se quisermos compartilhar um estado entre as crianças 4, 11 e 10 que estão distantes umas das outras na árvore? Mais uma vez, precisaríamos criar o estado no componente App e, em seguida, fazer vários níveis de perfuração de prop para passar o estado do App para esses componentes.

E à medida que o tempo passa e nosso aplicativo cresce em tamanho, ele começará a tornar nosso componente App ou qualquer outro componente pai comum desordenado com declarações de estado desnecessárias. Essas declarações não são usadas diretamente por esses componentes, mas são usadas por alguns de seus filhos mais distantes.

Desvantagens da Perfuração de Prop Multi-Step

Existem basicamente duas desvantagens com a perfuração de suporte multinível. Eles são:

  • Inchaço desnecessário de componentes: conforme discutido acima, à medida que nosso aplicativo aumenta de tamanho, alguns componentes pai comuns podem ficar inchados com declarações de estado desnecessárias. E esses componentes podem não usar diretamente essas declarações, mas podem ser usados ​​por alguns de seus filhos distantes. Alguns outros componentes também podem ficar inchados, que estão apenas agindo como transmissores de prop para um componente filho. Isso também afetará negativamente a legibilidade do código.
  • Rerenderização desnecessária : Rerenderização desnecessária é um grande não, não para um aplicativo do lado do cliente. Re-renderizações desnecessárias podem tornar um aplicativo lento, lento, sem resposta e proporcionar uma experiência ruim ao usuário. No React, as re-renderizações são causadas por mudanças de estado ou prop, entre outros motivos. Portanto, se um componente não estiver realmente usando um estado e estiver apenas agindo como uma passagem de pai para filho para os adereços, ele também poderá ser renderizado desnecessariamente quando o estado/props mudar. Veja a imagem abaixo para entender melhor

Grupo-52-1

A solução para este problema

É por isso que usamos um aplicativo de gerenciamento de estado como Redux ou MobX para lidar com os cenários acima de gerenciamento de estado de maneira mais uniforme e eficiente.

Nesse tipo de solução de gerenciamento de estado como o Redux, podemos criar um estado global e colocá-lo em uma loja. Qualquer componente que exija qualquer estado dessa loja pode obtê-lo facilmente assinando a loja. Desta forma, podemos nos livrar de ambas as desvantagens acima.

  • Desorganização de componentes: Obter o estado sob demanda do componente que está "realmente" usando-o pode desorganizar muitos de nossos componentes em grande parte, removendo todas as perfurações desnecessárias.
  • Chega de re-renderizações desnecessárias: Como não temos componentes que atuam apenas como passadores de prop, também evitamos re-renderizações desnecessárias desses componentes. Apenas os componentes que usam uma parte do estado global são renderizados novamente quando o estado muda, o que é um comportamento desejado.

O que você vai aprender aqui

Neste tutorial, você aprenderá como configurar seu próprio aplicativo React com Redux. Vamos criar um aplicativo de reação e configurar o redux para poder gerenciar o estado globalmente para que qualquer componente possa acessar qualquer parte do estado (daí o nome app de reação alimentado por redux). Algumas das outras alternativas de redux que se pode tentar são MobX, Zustand etc, mas para este artigo usaremos redux.

Veremos como criar a loja e conectá-la ao aplicativo. Também veremos como escrever ações e despachá-las nas interações do usuário. Então veremos como fazer redutores e atualizar a loja, ler a loja de outros componentes que são filhos do App e muito mais.

Também fornecerei todos os trechos de código importantes ao longo do caminho para que você possa ativar rapidamente o aplicativo enquanto lê e codifica.

Para lhe dar um vislumbre no início, é isso que vamos construir até o final:

finalAppDemo

Estaremos criando um aplicativo básico onde podemos adicionar e remover itens em um carrinho. Gerenciaremos as mudanças de estado na loja Redux e exibiremos as informações na interface do usuário.

Antes de começarmos

Antes de continuar com este tutorial, você deve estar familiarizado com a loja, as ações e os redutores do Redux.

Se não estiver, você pode ler meu último artigo que escrevi sobre Redux (se ainda não o fez): O que é Redux? Loja, ações e redutores explicados para iniciantes .

Isso ajudará você a entender o artigo atual. Neste tutorial anterior, tentei explicar os princípios/conceitos fundamentais do Redux. Eu abordei o que é a loja, quais são as ações e como os redutores funcionam. Também discuto o que torna o Redux previsível junto com um exemplo.

desprezível-me-minions

Configuração de código inicial

Vamos configurar tudo o que precisamos para o nosso projeto. Basta seguir estes passos e você estará pronto e funcionando em pouco tempo.

1. Crie um aplicativo React com o comando create-react-app

npx create-react-app react-app-with-redux

2. Vá para a pasta recém-criada

Basta digitar este comando para navegar até a nova pasta:

cd react-app-with-redux

3. Instale o Redux e as bibliotecas react-redux

Você pode instalar o Redux e react-redux assim:

npm install redux react-redux

4. Execute o aplicativo

Você pode executar seu novo aplicativo com o seguinte comando:

npm start

Como construir o aplicativo principal

5. Como criar o Redutor

Para criar um redutor, primeiro crie uma pasta dentro srcchamada actionTypes. Em seguida, crie um arquivo dentro dele chamado actionTypes.js. Este arquivo conterá todas as ações com as quais o aplicativo estará lidando.

Adicione as seguintes linhas em actionTypes.js:

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

Como nosso aplicativo terá a funcionalidade de adicionar e excluir itens, precisamos dos dois tipos de ação acima.

Em seguida, crie uma pasta dentro do srcchamado reducerse crie um novo arquivo nele chamado cartReducer.js. Este arquivo conterá toda a lógica do redutor relacionada ao componente do carrinho .

Nota : Vamos criar a view/UI na etapa 8, então espere por isso.

Adicione as seguintes linhas em cartReducer.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

Conforme discutimos no meu tutorial anterior , criamos um estado inicial para o aplicativo e o atribuímos ao parâmetro padrão de statena cartReducerfunção.

Esta função ativa o tipo de ação despachada. Em seguida, dependendo de qualquer caso que corresponda ao tipo de ação, ele faz as alterações necessárias no estado e retorna uma nova instância do estado atualizado.

Se nenhum dos tipos de ação corresponder, o estado será retornado como está.

Por fim, fazemos uma exportação padrão da cakeReducerfunção para usá-la no processo de criação da loja.

6. Como criar a loja e fornecê-la ao aplicativo

Crie um arquivo dentro srccom o nome store.jse crie a loja usando este comando:

const store = createStore()

Adicione as seguintes linhas em store.js:

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

Agora é hora de fornecer isso storeao Appcomponente. Para isso, usaremos a <Provider>tag que obtemos da react-reduxbiblioteca.

Envolvemos todo o Appcomponente dentro da <Provider>tag usando a seguinte sintaxe:

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

Ao envolver o Appcomponente dentro da <Provider>tag, todos os componentes filhos de Appobterão acesso ao store. Você pode ler meu artigo anterior sobre O que é Redux? Loja, ações e redutores explicados para iniciantes saberem mais.

Continuando com App.js, adicione as seguintes linhas ao arquivo:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. Crie as ações

Agora crie uma pasta dentro srcchamada actionse crie um arquivo dentro dela chamado cartAction.js. Aqui adicionaremos todas as ações a serem despachadas em algumas interações do usuário.

Adicione as seguintes linhas no cartAction.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

No código acima, criamos dois criadores de ação (funções JS puras que retornam actionobjeto) chamados addItem()e deleteItem(). Ambos os criadores de ação retornam actionobjetos com um type.

Nota : Cada actionobjeto deve ter um typevalor único. Junto com ele, quaisquer dados adicionais passados ​​com o objeto de ação são opcionais e dependerão da lógica utilizada para atualizar ostate

8. Como criar a visualização/IU

Agora que criamos todas as entidades necessárias, como store, actions e Reducers, é hora de criar os elementos da interface do usuário.

Crie uma componentpasta dentro srce um Cart.jsarquivo dentro dela. Adicione as seguintes linhas dentro de Cart.js:

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Adicione este Cartcomponente no App.jsarquivo:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

Apenas para torná-lo um pouco apresentável, adicionei um pouco de estilo básico da App.cssseguinte forma:

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

Esta é a aparência da interface do usuário a partir de agora:

Screenshot-2022-05-20-at-20.01.01

9. Como ler e acessar a loja usando o useSelectorgancho

useSelectoré um gancho fornecido pela biblioteca react-redux que nos ajuda a ler o storee seu(s) conteúdo(s).

Importe o gancho de react-reduxe use a seguinte sintaxe para ler o armazenamento com useSelectorgancho:

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

Depois de adicionar o useSelectorgancho, seu Cart.jsarquivo ficará assim:

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

O registro do estado do console nos dará o estado inicial que definimos no arquivo do redutor na etapa 5.

Captura de tela-2022-05-21-at-01.10.28

10. Como despachar uma ação ao clicar no botão com o useDispatchgancho

A biblioteca react-redux nos dá outro gancho chamado useDispatchgancho. Isso nos ajuda a despachar as ações ou criadores de ações que, por sua vez, retornam ações. A sintaxe é a seguinte:

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

Assim, adicionar um dispatcher ao nosso Cart.jsfinalmente fará com que o arquivo fique assim:

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

Observe como ao clicar no botão Adicionar item ao carrinho , nós, dispatcho criador da ação addItem()que criamos na etapa nº. 7.

Da mesma forma, ao clicar no botão Remover item do carrinho , despachamos o criador da ação com deleteItem().

A statevariável armazena o estado do aplicativo, que é basicamente um objeto com uma chave numOfItems. Então state.numOfItemsnos dá o valor atual do número de itens na loja.

Exibimos essas informações na exibição na linha <h2>Number of items in Cart: {state.numOfItems}</h2>.

Para aprofundar um pouco mais, quando um usuário clica no botão Adicionar item ao carrinho, ele despacha o addItem()criador da ação. Isso, por sua vez, retorna um actionobjeto com tipo type: ADD_ITEM.

Conforme mencionado no meu tutorial anterior , quando uma ação é despachada, todos os redutores ficam ativos.

Atualmente neste exemplo temos apenas um redutor – cartReducer. Assim, torna-se ativo e escuta o actiondespachado.

Conforme mostrado na etapa 5, o redutor recebe o estado e a ação como entrada, liga action typee retorna a nova instância do estado atualizado .

Neste exemplo, quando a ação com type: ADD_ITEMcorresponde ao primeiro caso de alternância, primeiro ela faz uma cópia de todo o estado usando o operador spread ...state. Em seguida, ele faz a atualização necessária – que no caso de adicionar itens é numOfItems: state.numOfItems + 1(ou seja, aumentar o numOfItemsem 1).

Da mesma forma, usando a mesma lógica, ao clicar no botão Remover Item do Carrinho, type: DELETE_ITEMé despachada uma ação com tipo que vai e diminui numOfItemsem 1.

Aqui está a demonstração do aplicativo em funcionamento:

finalAppDemo-1

Observe como conseguimos controlar o comportamento do botão Remover item do carrinho com base no valor de numOfItemsna loja Redux. Como um número negativo de itens não faz sentido, desabilitamos o botão Remover item do carrinho se state.numOfItems <= 0.

Dessa forma, conseguimos evitar que o usuário diminua o número de itens no carrinho se já for 0.

Este foi um exemplo básico para mostrar como podemos controlar o comportamento de vários elementos DOM com base no estado interno do aplicativo.

E aí vai! Acabamos de configurar nosso primeiro aplicativo React com Redux. Agora você pode criar vários outros componentes com base em seus requisitos e compartilhar um estado global comum entre eles.

Repositório do GitHub

Aqui está o repositório GitHub do projeto para que você possa examinar o código-fonte completo, se quiser: GitHub repo

Resumo

Neste artigo, aprendemos como criar rapidamente um aplicativo React com tecnologia Redux.

Ao longo do caminho, aprendemos a:

  • Crie ações, criadores de ações, redutores e a loja
  • Forneça a loja ao aplicativo usando<Provider>
  • Ler/acessar a loja de componentes usando o useSelectorgancho e exibir as informações de estado na interface do usuário
  • Despachar as ações em eventos do usuário, como cliques de botão, usando o useDispatchgancho
  • Controle o comportamento dos elementos DOM com lógica baseada no estado do aplicativo
  • Aprendemos quais são as desvantagens do gerenciamento de estado ineficiente e vários níveis de perfuração de hélices

 Fonte: https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

Como Construir Um Aplicativo React Alimentado Por Redux
Duong Tran

Duong Tran

1659637920

Cách Xây Dựng Một ứng Dụng React được Hỗ Trợ Bởi Redux

Vấn đề chúng tôi đang giải quyết

Trong nhiều trường hợp khi chúng ta muốn tạo một ứng dụng nhỏ, chúng ta có thể có một số thành phần khai báo và sử dụng trạng thái riêng của chúng. Và trong một số trường hợp, một thành phần có thể muốn chia sẻ trạng thái với các thành phần con trực tiếp của nó.

Chúng ta có thể xử lý những tình huống này chỉ bằng cách khai báo cục bộ các trạng thái trong một thành phần - và có thể chuyển trạng thái cho con của nó dưới dạng đạo cụ nếu cần (còn được gọi là khoan chống đỡ).

Nhưng nếu ứng dụng của bạn phát triển về kích thước, bạn có thể cần phải chuyển trạng thái cho một ứng dụng con, trạng thái này có thể là một vài bậc trong hệ thống phân cấp. Bạn cũng có thể cần sử dụng trạng thái chung giữa các thành phần anh em.

Chắc chắn, trong trường hợp chia sẻ trạng thái giữa các thành phần anh chị em, chúng ta có thể khai báo trạng thái trong cha mẹ của họ và sau đó chuyển trạng thái xuống cho con cái của họ bằng cách khoan prop. Nhưng điều đó có thể không phải lúc nào cũng khả thi và có những nhược điểm riêng mà chúng ta sẽ thấy một chút.

Chỉ cần xem xét sơ đồ sau:

Nhóm-49

Đây là một biểu diễn sơ đồ của cấu trúc tệp thành phần trong một ứng dụng React điển hình.

Giả sử chúng ta cần chia sẻ trạng thái chung giữa Trẻ 5 và Trẻ 6. Trong trường hợp đó, chúng ta rất có thể khai báo một trạng thái trong cha mẹ của chúng (tức là Trẻ 2) và chuyển trạng thái xuống cho hai trẻ (5 và 6) .

Tất cả tốt cho đến bây giờ. Nhưng nếu chúng ta cần có cùng một trạng thái trong Child 3 thì sao? Trong trường hợp đó, chúng tôi sẽ cần khai báo trạng thái trong cha / mẹ chung của Trẻ 5, 6 và 3 - tức là Thành phần ứng dụng.

Tương tự, điều gì sẽ xảy ra nếu chúng ta muốn chia sẻ trạng thái giữa các Trẻ em 4, 11 và 10 ở cách xa nhau trên cây? Một lần nữa, chúng tôi cần tạo trạng thái trong thành phần Ứng dụng và sau đó thực hiện nhiều cấp độ khoan chống để chuyển trạng thái từ Ứng dụng sang các thành phần này.

Và khi thời gian trôi qua và ứng dụng của chúng tôi phát triển về quy mô, nó sẽ bắt đầu làm cho thành phần Ứng dụng của chúng tôi hoặc bất kỳ thành phần mẹ chung nào khác trở nên lộn xộn với các khai báo trạng thái không cần thiết. Các khai báo này không được sử dụng trực tiếp bởi các thành phần này nhưng được sử dụng bởi một số người con xa của chúng.

Nhược điểm của Khoan dự phòng nhiều bước

Chủ yếu có hai nhược điểm với khoan chống đa cấp. Họ đang:

  • Sự phình to không cần thiết của các thành phần: Như đã thảo luận ở trên, khi ứng dụng của chúng tôi phát triển về kích thước, một số thành phần mẹ phổ biến có thể bị phình ra với các khai báo trạng thái không cần thiết. Và những thành phần này có thể không trực tiếp sử dụng những khai báo đó, nhưng chúng có thể được sử dụng bởi một số người con ở xa của họ. Một số thành phần khác cũng có thể bị phình ra, những thành phần này chỉ hoạt động như những người truyền hỗ trợ cho một thành phần con. Điều này cũng sẽ ảnh hưởng tiêu cực đến khả năng đọc mã.
  • Kết xuất không cần thiết: Kết xuất không cần thiết là điều tối kỵ đối với ứng dụng phía máy khách. Các kết xuất không cần thiết có thể khiến ứng dụng chậm, lag, không phản hồi và mang lại trải nghiệm người dùng không tốt. Trong React, các kết xuất được tạo ra bởi các thay đổi trạng thái hoặc prop, trong số các lý do khác. Vì vậy, nếu một thành phần không thực sự sử dụng trạng thái và chỉ hoạt động như một đoạn từ cha đến con cho các đạo cụ, thì nó cũng có thể được hiển thị lại một cách không cần thiết khi trạng thái / đạo cụ thay đổi. Xem hình dưới đây để hiểu rõ hơn

Nhóm-52-1

Giải pháp cho vấn đề này

Đây là lý do tại sao chúng tôi sử dụng ứng dụng quản lý nhà nước như Redux hoặc MobX để xử lý các tình huống quản lý nhà nước ở trên một cách thống nhất và hiệu quả hơn.

Với những giải pháp quản lý trạng thái như Redux, chúng ta có thể tạo một trạng thái toàn cầu và đưa nó vào một cửa hàng. Bất kỳ thành phần nào yêu cầu trạng thái nào từ cửa hàng đó có thể dễ dàng nhận được bằng cách đăng ký vào cửa hàng. Bằng cách này chúng ta có thể thoát khỏi cả hai nhược điểm trên.

  • Khai thác các thành phần: Nhận trạng thái theo yêu cầu từ thành phần "thực sự" đang sử dụng nó có thể giải mã nhiều thành phần của chúng ta ở mức độ lớn bằng cách loại bỏ tất cả các khoan chống đỡ không cần thiết.
  • Không còn kết xuất không cần thiết nữa: Vì chúng tôi không có các thành phần chỉ hoạt động như một trình chuyển hỗ trợ, chúng tôi cũng tránh kết xuất không cần thiết các thành phần đó. Chỉ các thành phần sử dụng một phần của trạng thái toàn cục mới hiển thị lại khi trạng thái thay đổi là một hành vi mong muốn.

Những gì bạn sẽ học ở đây

Trong hướng dẫn này, bạn sẽ học cách thiết lập ứng dụng React do Redux hỗ trợ. Chúng tôi sẽ tạo một ứng dụng phản ứng và thiết lập redux để có thể quản lý trạng thái trên toàn cầu để bất kỳ thành phần nào cũng có thể truy cập vào bất kỳ phần nào của trạng thái (do đó có tên là ứng dụng phản ứng được cung cấp bởi redux). Một số thay thế khác của redux mà người ta có thể thử là MobX, Zustand, v.v., nhưng đối với bài viết này, chúng tôi sẽ sử dụng redux.

Chúng ta sẽ đi qua cách tạo cửa hàng và kết nối nó với ứng dụng. Chúng tôi cũng sẽ xem cách viết các hành động và gửi chúng trên các tương tác của người dùng. Sau đó, chúng ta sẽ xem cách tạo bộ giảm và cập nhật cửa hàng, đọc cửa hàng từ các thành phần khác là con của Ứng dụng và hơn thế nữa.

Tôi cũng sẽ cung cấp tất cả các đoạn mã quan trọng trong quá trình thực hiện để bạn có thể nhanh chóng mở ứng dụng khi bạn đọc và viết mã.

Để cho bạn cái nhìn sơ lược về phần đầu, đây là những gì chúng tôi sẽ xây dựng ở phần cuối:

finalAppDemo

Chúng tôi sẽ tạo một ứng dụng cơ bản, nơi chúng tôi có thể thêm và xóa các mặt hàng trong giỏ hàng. Chúng tôi sẽ quản lý các thay đổi trạng thái trong cửa hàng Redux và hiển thị thông tin trong giao diện người dùng.

Trước khi chúng ta bắt đầu

Trước khi tiếp tục với hướng dẫn này, bạn nên làm quen với cửa hàng Redux, các hành động và bộ giảm bớt.

Nếu bạn chưa, bạn có thể xem qua bài viết cuối cùng của tôi mà tôi đã viết trên Redux (nếu bạn chưa viết): Redux là gì? Giải thích về Store, Actions và Reducers cho người mới bắt đầu .

Điều này sẽ giúp bạn hiểu bài viết hiện tại. Trong hướng dẫn trước đây, tôi đã cố gắng giải thích các nguyên tắc / khái niệm cơ bản của Redux. Tôi đã đề cập đến cửa hàng là gì, các hành động là gì và cách hoạt động của bộ giảm tốc. Tôi cũng thảo luận về những gì làm cho Redux có thể dự đoán được cùng với một ví dụ.

tay sai hèn hạ

Thiết lập mã ban đầu

Hãy lấy mọi thứ chúng ta cần thiết lập cho dự án của mình. Chỉ cần làm theo các bước sau và bạn sẽ thiết lập và chạy ngay lập tức.

1. Tạo ứng dụng React bằng lệnh create-react-app

npx create-react-app react-app-with-redux

2. Chuyển đến thư mục mới tạo

Chỉ cần gõ lệnh này để điều hướng đến thư mục mới:

cd react-app-with-redux

3. Cài đặt Redux và các thư viện react-redux

Bạn có thể cài đặt Redux và react-redux như sau:

npm install redux react-redux

4. Chạy ứng dụng

Bạn có thể chạy ứng dụng mới của mình bằng lệnh sau:

npm start

Cách xây dựng ứng dụng chính

5. Cách tạo Hộp giảm tốc

Để tạo một trình giảm bớt, trước tiên hãy tạo một thư mục bên trong srccó tên actionTypes. Sau đó, tạo một tệp bên trong nó có tên actionTypes.js. Tệp này sẽ chứa tất cả các hành động mà ứng dụng sẽ xử lý.

Thêm các dòng sau vào actionTypes.js:

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

Vì ứng dụng của chúng tôi sẽ có chức năng thêm và xóa các mục, chúng tôi cần hai loại hành động trên.

Tiếp theo, tạo một thư mục bên trong srcđược gọi reducersvà tạo một tệp mới có tên trong đó cartReducer.js. Tệp này sẽ chứa tất cả logic giảm thiểu liên quan đến thành phần giỏ hàng .

Lưu ý : Chúng tôi sẽ tạo chế độ xem / giao diện người dùng trong bước 8, vì vậy hãy chờ đợi điều đó.

Thêm các dòng sau vào cartReducer.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

Như chúng ta đã thảo luận trong hướng dẫn trước của mình , chúng ta đã tạo trạng thái ban đầu cho ứng dụng và gán nó cho tham số mặc định của statehàm cartReducer.

Chức năng này chuyển sang loại hành động được thực hiện . Sau đó, tùy thuộc vào bất kỳ trường hợp nào phù hợp với loại hành động, nó thực hiện các thay đổi cần thiết trong trạng thái và trả về một phiên bản mới mới của trạng thái đã cập nhật.

Nếu không có loại hành động nào khớp, thì trạng thái sẽ được trả về như ban đầu.

Cuối cùng, chúng tôi thực hiện xuất mặc định của cakeReducerhàm để sử dụng nó trong quá trình tạo cửa hàng.

6. Cách tạo cửa hàng và cung cấp cho ứng dụng

Tạo một tệp bên trong srcvới tên store.jsvà tạo cửa hàng bằng lệnh sau:

const store = createStore()

Thêm các dòng sau vào store.js:

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

Bây giờ là lúc cung cấp điều này storecho Appthành phần. Đối với điều này, chúng tôi sẽ sử dụng <Provider>thẻ mà chúng tôi nhận được từ react-reduxthư viện.

Chúng tôi bọc toàn bộ Appthành phần bên trong <Provider>thẻ bằng cú pháp sau:

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

Bằng cách gói Appthành phần bên trong <Provider>thẻ, tất cả thành phần con của Appsẽ có quyền truy cập vào store. Bạn có thể đọc bài viết trước của tôi về Redux là gì? Giải thích về Cửa hàng, Hành động và Giảm bớt cho Người mới bắt đầu biết thêm.

Tiếp tục App.js, thêm các dòng sau vào tệp:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. Tạo các Hành động

Bây giờ tạo một thư mục bên trong srccó tên actionsvà tạo một tệp bên trong nó có tên cartAction.js. Ở đây, chúng tôi sẽ thêm tất cả các hành động sẽ được thực hiện trên một số tương tác của người dùng.

Thêm các dòng sau vào cartAction.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

Trong đoạn mã trên, chúng tôi đã tạo hai trình tạo hành động (các hàm JS thuần túy trả về actionđối tượng) được gọi là addItem()deleteItem(). Cả hai trình tạo hành động đều trả về actioncác đối tượng với một cụ thể type.

Lưu ý : Mỗi actionđối tượng phải có một typegiá trị duy nhất. Cùng với nó, bất kỳ dữ liệu bổ sung nào được truyền với đối tượng hành động là tùy chọn và sẽ phụ thuộc vào logic được sử dụng để cập nhậtstate

8. Cách tạo chế độ xem / giao diện người dùng

Bây giờ chúng ta đã tạo tất cả các thực thể cần thiết như store, action và Reducers, đã đến lúc tạo các phần tử UI.

Tạo một componentthư mục bên trong srcvà một Cart.jstệp bên trong nó. Thêm các dòng sau vào bên trong Cart.js:

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Thêm Cartthành phần này vào App.jstệp:

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

Để làm cho nó dễ chịu hơn một chút, tôi đã thêm một chút kiểu dáng cơ bản App.cssnhư sau:

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

Đây là giao diện người dùng hiện tại:

Ảnh chụp màn hình-2022-05-20-at-20.01.01

9. Cách đọc và truy cập cửa hàng bằng useSelectorhook

useSelectorlà một hook được cung cấp bởi thư viện react-redux giúp chúng ta đọc store(các) nội dung của nó.

Nhập hook từ react-reduxvà sử dụng cú pháp sau để đọc store với useSelectorhook:

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

Sau khi thêm useSelectorhook, Cart.jstệp của bạn sẽ trông giống như sau:

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Bảng điều khiển ghi nhật ký trạng thái sẽ cung cấp cho chúng ta trạng thái ban đầu mà chúng ta đã đặt trong tệp giảm tốc ở bước 5.

Ảnh chụp màn hình-2022-05-21-at-01.10.28

10. Cách thực hiện một hành động khi nhấp vào nút bằng useDispatchmóc

Thư viện react-redux cung cấp cho chúng ta một hook khác được gọi là useDispatchhook. Nó giúp chúng tôi gửi các hành động hoặc người tạo hành động, từ đó trả lại các hành động. Cú pháp như sau:

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

Do đó, việc thêm một điều phối viên vào Cart.jscuối cùng sẽ làm cho tệp trông giống như sau:

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

Lưu ý rằng khi nhấp vào nút Thêm mặt hàng vào giỏ hàng , chúng tôi dispatchlà người tạo hành động addItem()mà chúng tôi đã tạo ở bước số không. 7.

Tương tự khi nhấp vào nút Xóa mặt hàng khỏi giỏ hàng , chúng tôi cử người tạo hành động đến deleteItem().

Biến statelưu trữ trạng thái của ứng dụng, về cơ bản là một đối tượng có khóa numOfItems. Vì vậy, state.numOfItemscung cấp cho chúng tôi giá trị số lượng mặt hàng hiện tại trong cửa hàng.

Chúng tôi hiển thị thông tin này ở dạng xem trong dòng <h2>Number of items in Cart: {state.numOfItems}</h2>.

Để tìm hiểu sâu hơn một chút, khi người dùng nhấp vào nút Thêm mặt hàng vào giỏ hàng, nó sẽ điều addItem()động người tạo hành động. Điều này, đến lượt nó, trả về một actionđối tượng có kiểu type: ADD_ITEM.

Như đã đề cập trong hướng dẫn trước của tôi , khi một hành động được gửi đi, tất cả các bộ giảm sẽ hoạt động.

Hiện tại trong ví dụ này, chúng tôi chỉ có một bộ giảm - cartReducer. Vì vậy, nó trở nên hoạt động và lắng nghe những gì được actiongửi đi.

Như được hiển thị trong bước 5, bộ giảm thiểu lấy trạng thái và hành động làm đầu vào, bật action typetrả về phiên bản mới mới của trạng thái đã cập nhật .

Trong ví dụ này, khi hành động với type: ADD_ITEMkhớp với trường hợp chuyển đổi đầu tiên, trước tiên nó tạo một bản sao của toàn bộ trạng thái bằng cách sử dụng toán tử spread ...state. Sau đó, nó thực hiện cập nhật cần thiết - trong trường hợp thêm các mục là numOfItems: state.numOfItems + 1(tức là tăng numOfItems1).

Tương tự, sử dụng logic tương tự, khi nhấp vào nút Xóa mặt hàng khỏi giỏ hàng, một hành động với loại type: DELETE_ITEMđược thực hiện sẽ đi và giảm đi numOfItems1.

Đây là bản demo của ứng dụng đang hoạt động:

finalAppDemo-1

Lưu ý cách chúng tôi có thể kiểm soát hành vi của nút Xóa mặt hàng khỏi giỏ hàng dựa trên giá trị của numOfItemstrong cửa hàng Redux. Vì số lượng mặt hàng âm không có ý nghĩa, chúng tôi đã vô hiệu hóa nút Xóa mặt hàng khỏi giỏ hàng nếu state.numOfItems <= 0.

Bằng cách này, chúng tôi có thể ngăn người dùng giảm số lượng mặt hàng trong giỏ hàng nếu nó đã là 0.

Đây là một ví dụ cơ bản để cho bạn thấy cách chúng tôi có thể kiểm soát hành vi của các phần tử DOM khác nhau dựa trên trạng thái bên trong của ứng dụng.

Và ở đó bạn đi! Chúng tôi vừa hoàn thành việc thiết lập ứng dụng React hỗ trợ Redux đầu tiên của mình. Bây giờ bạn có thể tiếp tục và tạo nhiều thành phần khác dựa trên yêu cầu của bạn và chia sẻ trạng thái toàn cầu chung giữa chúng.

GitHub Repo

Đây là repo GitHub của dự án để bạn có thể kiểm tra toàn bộ mã nguồn nếu bạn thích: GitHub repo

Bản tóm tắt

Trong bài viết này, chúng ta đã học cách tạo nhanh một ứng dụng React do Redux hỗ trợ.

Trên đường đi, chúng tôi đã học cách:

  • Tạo hành động, người tạo hành động, giảm bớt và cửa hàng
  • Cung cấp cửa hàng cho ứng dụng bằng cách sử dụng<Provider>
  • Đọc / truy cập cửa hàng từ các thành phần bằng cách sử dụng useSelectorhook và hiển thị thông tin trạng thái trong giao diện người dùng
  • Thực hiện các hành động trên các sự kiện của người dùng, chẳng hạn như nhấp vào nút, sử dụng useDispatchhook
  • Kiểm soát hành vi của các phần tử DOM bằng logic dựa trên trạng thái của ứng dụng
  • Chúng tôi đã tìm hiểu những nhược điểm của việc quản lý nhà nước hiệu quả và nhiều cấp độ của hệ thống khoan chống

 Nguồn: https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

Cách Xây Dựng Một ứng Dụng React được Hỗ Trợ Bởi Redux

Comment Créer Une Application React Alimentée Par Redux

Le problème que nous résolvons

Dans de nombreux cas, lorsque nous voulons créer une petite application, nous pouvons avoir des composants qui déclarent et utilisent leur propre état. Et dans quelques cas, un composant peut vouloir partager l'état avec ses enfants immédiats.

Nous pouvons gérer ces situations simplement en déclarant des états localement dans un composant - et peut-être transmettre l'état à ses enfants sous la forme d'accessoires si nécessaire (ce qui est également connu sous le nom de forage d'accessoires).

Mais si votre application grandit, vous devrez peut-être transmettre l'état à un enfant qui peut se trouver à plusieurs niveaux dans la hiérarchie. Vous devrez peut-être également utiliser un état commun entre les composants frères.

Bien sûr, dans le cas d'un partage d'état entre des composants frères, nous pouvons déclarer l'état dans leurs parents, puis transmettre l'état à leurs enfants par forage d'hélice. Mais cela n'est pas toujours faisable et a ses propres inconvénients que nous verrons dans un instant.

Considérez simplement le schéma suivant :

Groupe-49

Il s'agit d'une représentation schématique d'une structure de fichier de composant dans une application React typique.

Disons que nous devons partager un état commun entre l'enfant 5 et l'enfant 6. Dans ce cas, nous pouvons très bien déclarer un état dans leur parent (c'est-à-dire l'enfant 2) et transmettre l'état aux deux enfants (5 et 6) .

Tout va bien à partir de maintenant. Mais que se passe-t-il si nous devons avoir le même élément d'état dans Child 3 ? Dans ce cas, nous aurions besoin de déclarer l'état dans le parent/grand-parent commun des enfants 5, 6 et 3, c'est-à-dire le composant App.

De même, que se passe-t-il si nous voulons partager un état entre les enfants 4, 11 et 10 qui sont éloignés les uns des autres dans l'arbre ? Nous aurions à nouveau besoin de créer l'état dans le composant App, puis d'effectuer plusieurs niveaux de forage d'accessoires pour transmettre l'état de App à ces composants.

Et au fur et à mesure que le temps passe et que notre application grandit, elle commencera à rendre notre composant App ou tout autre composant parent commun encombré de déclarations d'état inutiles. Ces déclarations ne sont pas utilisées directement par ces composants mais sont utilisées par certains de leurs enfants éloignés.

Inconvénients du forage en plusieurs étapes

Il y a principalement deux inconvénients avec le forage à plusieurs niveaux. Elles sont:

  • Gonflement inutile des composants : comme indiqué ci-dessus, à mesure que notre application grandit, certains composants parents communs peuvent être gonflés avec des déclarations d'état inutiles. Et ces composants peuvent ne pas utiliser directement ces déclarations, mais ils peuvent être utilisés par certains de leurs enfants distants. Certains autres composants peuvent également être gonflés et agissent simplement comme des passeurs d'accessoires vers un composant enfant. Cela affectera également négativement la lisibilité du code.
  • Re-rendu inutile : Le re-rendu inutile est un grand non non pour une application côté client. Les re-rendus inutiles peuvent rendre une application lente, lente, insensible et donner une mauvaise expérience utilisateur. Dans React, les rendus sont causés par des changements d'état ou d'accessoire, entre autres raisons. Ainsi, si un composant n'utilise pas réellement d'état et n'agit que comme un passage du parent à l'enfant pour les accessoires, il peut également être restitué inutilement lorsque l'état/les accessoires changent. Voir l'image ci-dessous pour mieux comprendre

Groupe-52-1

La solution à ce problème

C'est pourquoi nous utilisons une application de gestion d'état comme Redux ou MobX pour gérer les scénarios de gestion d'état ci-dessus de manière plus uniforme et efficace.

Dans ce type de solutions de gestion d'état comme Redux, nous pouvons créer un état global et le mettre dans un magasin. Quel que soit le composant nécessitant un état de ce magasin, vous pouvez facilement l'obtenir en vous abonnant au magasin. De cette façon, nous pouvons nous débarrasser des deux inconvénients ci-dessus.

  • Désencombrement des composants : obtenir l'état à la demande du composant qui l'utilise "réellement" peut désencombrer un grand nombre de nos composants dans une large mesure en supprimant tous les perçages d'accessoires inutiles.
  • Finis les re-rendus inutiles : comme nous n'avons pas de composants qui agissent simplement comme passeur d'accessoires, nous évitons également les re-rendus inutiles de ces composants. Seuls les composants qui utilisent une partie de l'état global sont restitués lorsque l'état change, ce qui est un comportement souhaité.

Ce que vous apprendrez ici

Dans ce didacticiel, vous apprendrez à configurer votre propre application React alimentée par Redux. Nous allons créer une application de réaction et configurer redux pour pouvoir gérer l'état globalement afin que n'importe quel composant puisse accéder à n'importe quelle partie de l'état (d'où le nom d'application de réaction alimentée par redux). Certaines des autres alternatives de redux que l'on peut essayer sont MobX, Zustand, etc., mais pour cet article, nous utiliserons redux.

Nous verrons comment créer la boutique et la connecter à l'application. Nous verrons également comment écrire des actions et les répartir sur les interactions des utilisateurs. Ensuite, nous verrons comment créer des réducteurs et mettre à jour le magasin, lire le magasin à partir d'autres composants qui sont des enfants d'App, et bien plus encore.

Je fournirai également tous les extraits de code importants en cours de route afin que vous puissiez rapidement lancer l'application au fur et à mesure que vous lisez et codez.

Pour vous donner un aperçu au début, voici ce que nous allons construire à la fin :

finalAppDemo

Nous allons créer une application de base où nous pouvons ajouter et supprimer des articles dans un panier. Nous gérerons les changements d'état dans le magasin Redux et afficherons les informations dans l'interface utilisateur.

Avant de commencer

Avant de poursuivre ce didacticiel, vous devez vous familiariser avec le magasin Redux, les actions et les réducteurs.

Si ce n'est pas le cas, vous pouvez parcourir mon dernier article que j'ai écrit sur Redux (si vous ne l'avez pas encore fait) : Qu'est-ce que Redux ? Magasin, actions et réducteurs expliqués pour les débutants .

Cela vous aidera à comprendre l'article actuel. Dans ce tutoriel précédent, j'ai essayé d'expliquer les principes/concepts fondamentaux de Redux. J'ai couvert ce qu'est le magasin, quelles sont les actions et comment fonctionnent les réducteurs. Je discute également de ce qui rend Redux prévisible avec un exemple.

moi-moche-les-minions

Configuration initiale du code

Mettons en place tout ce dont nous avons besoin pour notre projet. Suivez simplement ces étapes et vous serez opérationnel en un rien de temps.

1. Créez une application React avec la commande create-react-app

npx create-react-app react-app-with-redux

2. Allez dans le dossier nouvellement créé

Tapez simplement cette commande pour accéder au nouveau dossier :

cd react-app-with-redux

3. Installez Redux et les bibliothèques react-redux

Vous pouvez installer Redux et react-redux comme ceci :

npm install redux react-redux

4. Exécutez l'application

Vous pouvez exécuter votre nouvelle application avec la commande suivante :

npm start

Comment créer l'application principale

5. Comment créer le réducteur

Pour créer un réducteur, créez d'abord un dossier à l'intérieur srcnommé actionTypes. Créez ensuite un fichier à l'intérieur nommé actionTypes.js. Ce fichier contiendra toutes les actions que l'application traitera.

Ajoutez les lignes suivantes dans actionTypes.js:

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

Étant donné que notre application aura la fonctionnalité d'ajouter et de supprimer des éléments, nous avons besoin des deux types d'action ci-dessus.

Créez ensuite un dossier à l'intérieur du fichier srcappelé reducerset créez-y un nouveau fichier nommé cartReducer.js. Ce fichier contiendra toute la logique du réducteur liée au composant du panier .

Remarque : Nous créerons la vue/l'interface utilisateur à l'étape 8, alors attendez pour cela.

Ajoutez les lignes suivantes dans cartReducer.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

Comme nous en avons discuté dans mon tutoriel précédent , nous avons créé un état initial pour l'application et l'avons affecté au paramètre par défaut de statedans la cartReducerfonction.

Cette fonction active le type d'action envoyée. Ensuite, selon le cas correspondant au type d'action, il apporte les modifications nécessaires à l'état et renvoie une nouvelle instance de l'état mis à jour.

Si aucun des types d'action ne correspond, l'état est renvoyé tel quel.

Enfin, nous effectuons une exportation par défaut de la cakeReducerfonction pour l'utiliser dans le processus de création de la boutique.

6. Comment créer le magasin et le fournir à l'application

Créez un fichier à l'intérieur srcavec le nom store.jset créez le magasin en utilisant cette commande :

const store = createStore()

Ajoutez les lignes suivantes dans store.js:

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

Il est maintenant temps de fournir ceci storeau Appcomposant. Pour cela, nous utiliserons la <Provider>balise que nous recevons de la react-reduxbibliothèque.

Nous encapsulons l'ensemble du Appcomposant dans la <Provider>balise en utilisant la syntaxe suivante :

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

En enveloppant le Appcomposant à l'intérieur de la <Provider>balise, tous les composants enfants de Appauront accès au store. Vous pouvez lire mon article précédent sur Qu'est-ce que Redux ? Magasin, actions et réducteurs expliqués pour les débutants pour en savoir plus.

En continuant avec App.js, ajoutez les lignes suivantes au fichier :

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. Créez les actions

Créez maintenant un dossier à l'intérieur srcappelé actionset créez un fichier à l'intérieur appelé cartAction.js. Nous allons ajouter ici toutes les actions à dispatcher sur certaines interactions utilisateur.

Ajoutez les lignes suivantes dans le cartAction.js:

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

Dans le code ci-dessus, nous avons créé deux créateurs d'action (fonctions JS pures qui renvoient un actionobjet) appelés addItem()et deleteItem(). Les deux créateurs d'action renvoient actiondes objets avec un fichier type.

Remarque : Chaque actionobjet doit avoir une valeur unique type. Parallèlement, toute donnée supplémentaire transmise avec l'objet d'action est facultative et dépendra de la logique utilisée pour mettre à jour lestate

8. Comment créer la vue/UI

Maintenant que nous avons créé toutes les entités requises telles que le magasin, les actions et les réducteurs, il est temps de créer les éléments de l'interface utilisateur.

Créez un componentdossier à l'intérieur srcet un Cart.jsfichier à l'intérieur. Ajoutez les lignes suivantes à l'intérieur Cart.js:

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

Ajoutez ce Cartcomposant dans le App.jsfichier :

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

Juste pour le rendre un peu présentable, j'ai ajouté un peu de style de base App.csscomme suit :

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

Voici à quoi ressemble l'interface utilisateur à partir de maintenant :

Capture d'écran-2022-05-20-at-20.01.01

9. Comment lire et accéder au magasin en utilisant le useSelectorcrochet

useSelectorest un hook fourni par la bibliothèque react-redux qui nous aide à lire le storeet son(ses) contenu(s).

Importez le crochet depuis react-reduxet utilisez la syntaxe suivante pour lire le magasin avec le useSelectorcrochet :

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

Après avoir ajouté le useSelectorcrochet, votre Cart.jsfichier ressemblera à ceci :

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

La journalisation de l'état par la console nous donnera l'état initial que nous avons défini dans le fichier du réducteur à l'étape 5.

Capture d'écran-2022-05-21-at-01.10.28

10. Comment envoyer une action sur un clic de bouton avec le useDispatchcrochet

La bibliothèque react-redux nous donne un autre crochet appelé le useDispatchcrochet. Cela nous aide à répartir les actions ou les créateurs d'actions qui, à leur tour, renvoient des actions. La syntaxe est la suivante :

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

Ainsi, l'ajout d'un répartiteur dans notre Cart.jsfera finalement ressembler le fichier à ceci :

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

Notez comment, en cliquant sur le bouton Ajouter un article au panier , nous sommes dispatchle créateur de l'action addItem()que nous avons créé à l'étape no. sept.

De même, en cliquant sur le bouton Supprimer l'article du panier , nous envoyons le créateur de l'action avec deleteItem().

La statevariable stocke l'état de l'application, qui est essentiellement un objet avec une clé numOfItems. Nous state.numOfItemsdonne donc la valeur actuelle du nombre d'articles dans le magasin.

Nous affichons ces informations dans la vue de la ligne <h2>Number of items in Cart: {state.numOfItems}</h2>.

Pour creuser un peu plus, lorsqu'un utilisateur clique sur le bouton Ajouter un article au panier, il envoie le addItem()créateur de l'action. Ceci, à son tour, renvoie un actionobjet de type type: ADD_ITEM.

Comme mentionné dans mon tutoriel précédent , lorsqu'une action est dispatchée, tous les réducteurs deviennent actifs.

Actuellement, dans cet exemple, nous n'avons qu'un seul réducteur - cartReducer. Il devient alors actif et écoute les actiondispatchés.

Comme indiqué à l'étape 5, le réducteur prend l'état et l'action en entrée, active action typeet renvoie la nouvelle instance de l'état mis à jour .

Dans cet exemple, lorsque l'action avec type: ADD_ITEMcorrespond au premier cas de commutation, elle crée d'abord une copie de l'état entier à l'aide de l'opérateur de propagation ...state. Ensuite, il effectue la mise à jour nécessaire - qui, dans le cas de l'ajout d'éléments, est numOfItems: state.numOfItems + 1(c'est-à-dire l'augmentation numOfItemsde 1).

De même, en utilisant la même logique, en cliquant sur le bouton Supprimer l'article du panier, une action de type type: DELETE_ITEMest envoyée qui va et diminue numOfItemsde 1.

Voici la démo de l'application de travail :

finalAppDemo-1

Remarquez comment nous avons pu contrôler le comportement du bouton Supprimer l'article du panier en fonction de la valeur de numOfItemsdans le magasin Redux. Comme un nombre négatif d'articles n'a pas de sens, nous avons désactivé le bouton Supprimer l'article du panier si state.numOfItems <= 0.

De cette façon, nous pouvons empêcher l'utilisateur de réduire le nombre d'articles dans le panier s'il est déjà à 0.

Ceci était un exemple de base pour vous montrer comment nous pouvons contrôler le comportement de divers éléments DOM en fonction de l'état interne de l'application.

Et voilà ! Nous venons de terminer la configuration de notre première application React alimentée par Redux. Vous pouvez maintenant continuer et créer divers autres composants en fonction de vos besoins et partager un état global commun entre eux.

Dépôt GitHub

Voici le référentiel GitHub du projet afin que vous puissiez examiner le code source complet si vous le souhaitez : référentiel GitHub

Sommaire

Dans cet article, nous avons appris à lancer rapidement une application React alimentée par Redux.

En cours de route, nous avons appris à :

  • Créer des actions, des créateurs d'action, des réducteurs et le magasin
  • Fournir le magasin à l'application en utilisant<Provider>
  • Lire/accéder au magasin à partir des composants à l'aide du useSelectorcrochet et afficher les informations d'état dans l'interface utilisateur
  • Distribuez les actions sur les événements utilisateur tels que les clics de bouton, à l'aide du useDispatchcrochet
  • Contrôlez le comportement des éléments DOM avec une logique basée sur l'état de l'application
  • Nous avons appris quels sont les inconvénients d'une gestion d'état inefficace et de plusieurs niveaux de forage d'accessoires

 Source : https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

Comment Créer Une Application React Alimentée Par Redux
渚  直樹

渚 直樹

1659634200

Redux を利用した React アプリを構築する方法

私たちが解決している問題

多くの場合、小さなアプリケーションを作成する場合、独自の状態を宣言して使用するコンポーネントがいくつかある場合があります。また、場合によっては、コンポーネントが直接の子と状態を共有したい場合があります。

これらの状況は、コンポーネント内でローカルに状態を宣言するだけで処理できます。また、必要に応じて状態を props の形で子に渡すこともできます (これは prop drilling とも呼ばれます)。

しかし、アプリケーションのサイズが大きくなると、子に状態を渡すことが必要になる場合があります。これは、階層の数ステップ下にある可能性があります。兄弟コンポーネント間で共通の状態を使用する必要がある場合もあります。

確かに、兄弟コンポーネント間で状態を共有する場合は、親で状態を宣言し、小道具のドリルによってその状態を子に渡すことができます。しかし、それは常に実現可能であるとは限らず、後で説明する独自の欠点があります.

次の図を考えてみてください。

グループ-49

これは、典型的な React アプリケーションにおけるコンポーネント ファイル構造の概略図です。

子 5 と子 6 の間で共通の状態を共有する必要があるとします。その場合、親 (つまり、子 2) で状態を宣言し、その状態を 2 つの子 (5 と 6) に渡すことができます。 .

今のところ大丈夫です。しかし、Child 3 に同じ状態が必要な場合はどうなるでしょうか? その場合、子 5、6、3 の共通の親/祖父母、つまり App コンポーネントで状態を宣言する必要があります。

同様に、ツリー内で互いに遠く離れている子 4、11、および 10 の間で状態を共有したい場合はどうなるでしょうか? App コンポーネントで状態を作成し、App からこれらのコンポーネントに状態を渡すために、複数レベルのプロップ ドリルを実行する必要があります。

時間が経ち、アプリのサイズが大きくなると、アプリ コンポーネントやその他の共通の親コンポーネントが不要な状態宣言で雑然とし始めます。これらの宣言は、これらのコンポーネントによって直接使用されることはありませんが、いくつかの下位の子によって使用されます。

マルチステッププロペラ掘削のデメリット

マルチレベルの支柱掘削には、主に 2 つの欠点があります。彼らです:

  • コンポーネントの不必要な肥大化:上で説明したように、アプリのサイズが大きくなると、一部の共通の親コンポーネントが不必要な状態宣言で肥大化する可能性があります。また、これらのコンポーネントはこれらの宣言を直接使用しない可能性がありますが、遠い子の一部によって使用される可能性があります。子コンポーネントへの prop passer として機能している他のコンポーネントも肥大化する可能性があります。これは、コードの可読性にも悪影響を及ぼします。
  • 不必要な再レンダリング:不必要な再レンダリングは、クライアント側のアプリケーションにとっては大したことではありません。不要な再レンダリングは、アプリを遅くしたり、ラグを発生させたり、応答を鈍らせたり、ユーザー エクスペリエンスを低下させたりする可能性があります。React では、再レンダリングは状態やプロップの変更などの理由で発生します。そのため、コンポーネントが実際には状態を使用しておらず、小道具の親から子への通路としてのみ機能している場合、状態/小道具が変更されたときに不必要に再レンダリングされる可能性もあります。それをよりよく理解するために下の写真を見てください

グループ-52-1

この問題の解決策

これが、Redux や MobX などの状態管理アプリを使用して、上記の状態管理のシナリオをより均一かつ効率的な方法で処理する理由です。

Redux のようなこの種の状態管理ソリューションでは、グローバルな状態を作成してストアに配置できます。そのストアからの状態を必要とするコンポーネントは、ストアをサブスクライブすることで簡単に取得できます。このようにして、上記の両方の欠点を取り除くことができます。

  • コンポーネントの整頓:コンポーネントを「実際に」使用しているコンポーネントからオンデマンドで状態を取得すると、不要なプロップ ドリルをすべて削除することで、多くのコンポーネントを大幅に整頓できます。
  • 不要な再レンダリングはもうありません:単に小道具のパサーとして機能するコンポーネントがないため、これらのコンポーネントの不要な再レンダリングも回避します。状態が変更されたときに、グローバル状態の一部を使用するコンポーネントのみが再レンダリングされます。これは望ましい動作です。

ここで学べること

このチュートリアルでは、独自の Redux を利用した React アプリケーションをセットアップする方法を学びます。反応アプリケーションを作成し、状態をグローバルに管理できるように redux をセットアップして、任意のコンポーネントが状態の任意の部分にアクセスできるようにします (したがって、redux を利用した反応アプリという名前です)。試すことができる redux の他の代替手段には、MobX、Zustand などがありますが、この記事では redux を使用します。

ストアを作成してアプリケーションに接続する方法について説明します。また、アクションを作成し、ユーザー インタラクションにディスパッチする方法についても説明します。次に、レデューサーを作成してストアを更新する方法、App の子である他のコンポーネントからストアを読み取る方法などについて説明します。

また、途中ですべての重要なコード スニペットを提供するので、読みながらコーディングしながらアプリケーションをすばやく起動できます。

最初に垣間見ることができるように、これが最後に構築するものです。

finalAppDemo

カート内のアイテムを追加および削除できる基本的なアプリケーションを作成します。Redux ストアで状態の変化を管理し、UI に情報を表示します。

始める前に

このチュートリアルに進む前に、Redux ストア、アクション、およびレデューサーについて理解しておく必要があります。

そうでない場合は、私が Redux について書いた前回の記事を読んでください (まだ読んでいない場合): Redux とは? 初心者向けのストア、アクション、リデューサーの説明

これは、現在の記事を理解するのに役立ちます。この前のチュートリアルでは、Redux の基本原則/概念を説明しようとしました。ストアとは何か、アクションとは何か、そしてレデューサーがどのように機能するかについて説明しました。また、Redux が予測可能である理由についても、例を挙げて説明します。

怪盗グルーのミニオンズ

初期コード設定

プロジェクトのセットアップに必要なものをすべて入手しましょう。これらの手順に従うだけで、すぐに稼働できます。

1. create-react-app コマンドで React アプリを作成する

npx create-react-app react-app-with-redux

2. 新しく作成したフォルダに移動します

次のコマンドを入力して、新しいフォルダーに移動します。

cd react-app-with-redux

3. Redux と react-redux ライブラリをインストールする

次のように Redux と react-redux をインストールできます。

npm install redux react-redux

4. アプリケーションを実行する

次のコマンドを使用して、新しいアプリを実行できます。

npm start

メインアプリの構築方法

5. Reducer の作成方法

レデューサーを作成するには、まずsrc名前付きのフォルダーを作成しますactionTypes。次に、その中に という名前のファイルを作成しますactionTypes.js。このファイルには、アプリケーションが処理するすべてのアクションが含まれます。

に次の行を追加しますactionTypes.js

export const ADD_ITEM = "ADD_ITEM";
export const DELETE_ITEM = "DELETE_ITEM";

このアプリにはアイテムを追加および削除する機能があるため、上記の 2 つのアクション タイプが必要です。

次に、src呼び出された内にフォルダーを作成reducersし、その中に という名前の新しいファイルを作成しますcartReducer.jsこのファイルには、カートコンポーネントに関連するすべてのレデューサー ロジックが含まれます。

: 手順 8 でビュー/UI を作成するので、そのままお待ちください。

に次の行を追加しますcartReducer.js

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const initialState = {
  numOfItems: 0,
};

export default const cartReducer = (state = initialState, action) => {
  switch (action.type) {
    case ADD_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems + 1,
      };

    case DELETE_ITEM:
      return {
        ...state,
        numOfItems: state.numOfItems - 1,
      };
    default:
      return state;
  }
};

前のチュートリアルで説明したように、アプリの初期状態を作成stateし、関数の既定のパラメーターに割り当てましたcartReducer

この関数は、ディスパッチされるアクションのタイプをオンにします。次に、アクション タイプに一致するケースに応じて、状態に必要な変更を加え、更新された状態の新しいインスタンスを返します。

どのアクション タイプも一致しない場合は、状態がそのまま返されます。

最後に、関数のデフォルトのエクスポートcakeReducerを作成して、ストア作成プロセスで使用します。

6. ストアの作成方法とアプリへの提供方法

src名前で内部にファイルをstore.js作成し、次のコマンドを使用してストアを作成します。

const store = createStore()

に次の行を追加しますstore.js

import { createStore } from "redux";
import { cartReducer } from "./reducers/cartReducer";

const store = createStore(cartReducer);

export default store;

これstoreAppコンポーネントに提供します。このために、ライブラリ<Provider>から取得したタグを使用します。react-redux

次の構文を使用して、Appコンポーネント全体をタグ内にラップします。<Provider>

// rest of the code ...

<Provider store={store}>
        <div>App Component</div>
        // child components of App/ other logic
</Provider>

// rest of the code ...

タグApp内にコンポーネントをラップすることにより、 のすべての子コンポーネントが. Redux とは?に関する以前の記事を読むことができます。初心者向けのストア、アクション、リデューサーの説明<Provider>Appstore

に進みApp.js、次の行をファイルに追加します。

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";

function App() {
  return (
    <Provider store={store}>
      <div>App Component</div>
    </Provider>
  );
}

export default App;

7. アクションを作成する

という名前の中にフォルダーを作成し、その中にsrcというactions名前のファイルを作成しますcartAction.js。ここでは、一部のユーザー インタラクションでディスパッチされるすべてのアクションを追加します。

に次の行を追加しますcartAction.js

import { ADD_ITEM, DELETE_ITEM } from "../actionTypes/actionTypes";

const addItem = () => {
  return {
    type: ADD_ITEM,
  };
};

const deleteItem = () => {
  return {
    type: DELETE_ITEM,
  };
};

export { addItem, deleteItem };

上記のコードでは、 と という 2 つのアクション作成者 (actionオブジェクトを返す純粋な JS 関数)addItem()を作成しましdeleteItem()た。どちらのアクション作成者もaction、特定の を持つオブジェクトを返しますtype

: 各actionオブジェクトには一意のtype値が必要です。それに加えて、アクション オブジェクトで渡される追加データはオプションであり、オブジェクトの更新に使用されるロジックに依存します。state

8. ビュー・UIの作り方

ストア、アクション、リデューサーなどの必要なエンティティをすべて作成したので、UI 要素を作成します。

componentその中にフォルダを作成し、その中srcCart.jsファイルを作成します。内に次の行を追加しますCart.js

import React from "react";

const Cart = () => {
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

CartこのコンポーネントをApp.jsファイルに追加します。

import "./App.css";
import { Provider } from "react-redux";
import store from "./store";
import Cart from "./component/Cart";

function App() {
  return (
    <Provider store={store}>
      <Cart />
    </Provider>
  );
}

export default App;

少し見栄えを良くするために、App.css次のように基本的なスタイリングを少し追加しました。

button {
  margin: 10px;
  font-size: 16px;
  letter-spacing: 2px;
  font-weight: 400;
  color: #fff;
  padding: 23px 50px;
  text-align: center;
  display: inline-block;
  text-decoration: none;
  border: 0px;
  cursor: pointer;
}
.green {
  background-color: rgb(6, 172, 0);
}
.red {
  background-color: rgb(221, 52, 66);
}
.red:disabled {
  background-color: rgb(193, 191, 191);
  cursor: not-allowed;
}
.cart {
  text-align: center;
}

現在の UI は次のようになります。

スクリーンショット-2022-05-20-at-20.01.01

9.useSelectorフックを使用してストアを読み取り、アクセスする方法

useSelectorとそのコンテンツを読み取るのに役立つ、 react-reduxライブラリによって提供されるフックです。store

からフックをインポートし、次の構文を使用してフックreact-reduxでストアを読み取ります。useSelector

import { useSelector } from "react-redux";
// rest of the code
const state = useSelector((state) => state);

// rest of the code

useSelectorフックを追加すると、Cart.jsファイルは次のようになります。

import React from "react";
import { useSelector } from "react-redux";

const Cart = () => {
  const state = useSelector((state) => state);
  console.log("store", state);
  return (
    <div className="cart">
      <h2>Number of items in Cart:</h2>
      <button className="green">Add Item to Cart</button>
      <button className="red">Remove Item from Cart</button>
    </div>
  );
};

export default Cart;

状態をコンソールに記録すると、ステップ 5 でレデューサー ファイルに設定した初期状態が得られます。

スクリーンショット-2022-05-21-at-01.10.28

10.フックでボタンクリック時にアクションをディスパッチする方法useDispatch

react-redux ライブラリは、フックと呼ばれる別のフックを提供しuseDispatchます。これは、アクションまたはアクション クリエーターをディスパッチし、アクションを返すのに役立ちます。構文は次のとおりです。

const dispatch = useDispatch();

dispatch(actionObject or calling the action creator);

したがって、ディスパッチャーを追加するCart.jsと、最終的にファイルは次のようになります。

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { addItem, deleteItem } from "../actions/cartAction";

const Cart = () => {
  const state = useSelector((state) => state);
  const dispatch = useDispatch();
  return (
    <div className="cart">
      <h2>Number of items in Cart: {state.numOfItems}</h2>
      <button
        onClick={() => {
          dispatch(addItem());
        }}
      >
        Add Item to Cart
      </button>
      <button
        disabled={state.numOfItems > 0 ? false : true}
        onClick={() => {
          dispatch(deleteItem());
        }}
      >
        Remove Item to Cart
      </button>
    </div>
  );
};

export default Cart;

[アイテムをカートに追加] ボタンをクリックすると、ステップ no. で作成しdispatchたアクション クリエータがどのように作成されるかに注目してください。addItem()7。

同様に、[カートからアイテムを削除]ボタンをクリックすると、アクション作成者に が送信されdeleteItem()ます。

このstate変数は、基本的にキーを持つオブジェクトであるアプリの状態を格納しますnumOfItems。したがってstate.numOfItems、ストア内の現在のアイテム数の値が得られます。

この情報を行のビューに表示します<h2>Number of items in Cart: {state.numOfItems}</h2>

もう少し詳しく説明すると、ユーザーが [カートにアイテムを追加] ボタンをクリックすると、addItem()アクション クリエーターがディスパッチされます。actionこれは、 type のオブジェクトを返しますtype: ADD_ITEM

前のチュートリアルで述べたように、アクションがディスパッチされると、すべてのレデューサーがアクティブになります。

現在、この例では、レデューサーは 1 つだけcartReducerです。actionそのため、アクティブになり、ディスパッチをリッスンします。

ステップ 5 に示すように、リデューサーは状態とアクションを入力として受け取り、 をオンにして、更新された状態の新しいインスタンスを返しaction typeます。

この例では、アクション withtype: ADD_ITEMが最初の switch ケースに一致すると、最初にスプレッド演算子を使用して状態全体のコピーを作成します...state。次に、必要な更新を行います。これは、アイテムを追加する場合numOfItems: state.numOfItems + 1(つまり、numOfItemsを 1 ずつ増やします) です。

同様に、同じロジックを使用して、Remove Item from Cart ボタンをクリックすると、type のアクションtype: DELETE_ITEMがディスパッチさnumOfItemsれ、1 ずつ減少します。

動作中のアプリのデモは次のとおりです。

finalAppDemo-1

numOfItemsRedux ストアの値に基づいて、[カートからアイテムを削除] ボタンの動作を制御できたことに注目してください。負の数のアイテムは意味がないため、[カートからアイテムを削除] ボタンを無効にしましたstate.numOfItems <= 0

このようにして、ユーザーがカート内のアイテムの数がすでに 0 になっている場合にそれを減らすことを防ぐことができます。

これは、アプリの内部状態に基づいてさまざまな DOM 要素の動作を制御する方法を示す基本的な例です。

そして、そこに行きます!最初の Redux を利用した React アプリケーションのセットアップが完了しました。これで、要件に基づいて他のさまざまなコンポーネントを作成し、それらの間で共通のグローバル状態を共有できるようになりました。

GitHub リポジトリ

プロジェクトの GitHub リポジトリは次のとおりです。必要に応じて完全なソース コードを調べることができます: GitHub リポジトリ

概要

この記事では、Redux を利用した React アプリケーションをすばやく起動する方法を学びました。

その過程で、次の方法を学びました。

  • アクション、アクション クリエーター、リデューサー、およびストアを作成する
  • を使用してストアをアプリに提供する<Provider>
  • useSelectorフックを使用してコンポーネントからストアを読み取り/アクセスし、UI に状態情報を表示します
  • useDispatchフックを使用して、ボタン クリックなどのユーザー イベントでアクションをディスパッチします。
  • アプリケーションの状態に基づいたロジックで DOM 要素の動作を制御する
  • 非効率的な状態管理と複数レベルの支柱掘削の欠点を学びました

 ソース: https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

 #redux #react 

Redux を利用した React アプリを構築する方法

How to Build a Redux-Powered React App

The Problem We're Solving

In many cases when we want to create a small application, we might have some components that declare and use their own state. And in a few cases, a component might want to share the state with its immediate children.

We can handle these situations just by declaring states locally within a component – and maybe pass the state to its children in the form of props if needed (which is also known as prop drilling).

 See more at: https://www.freecodecamp.org/news/how-to-build-a-redux-powered-react-app/

#redux #react 

How to Build a Redux-Powered React App
Rocio  O'Keefe

Rocio O'Keefe

1659585900

Dart_board_locator: Redux Extensions for Dart Board

dart_board_locator

Service/State Locator Service

What is a service locator

Simply put, it locates services. And if it can't do that it builds them.

You provide factories in the form of AppDecorations.

You can then use locate<T>({instance_id=""}) like magic to get the instance anywhere. locateAndBuild<YourChangeNotifier>((ctx, value)=>Text(value.someData))

When to use it?

When tree heirarchy of your services don't matter (i.e. they are "globals").

However you can store multiple instances if you key them or form a library.

Usage

Provide factories to construct your objects.

provide

In your appDecorations LocatorDecoration<SomeService>(()=>SomeServiceImpl()) if you want to use an interface.

or just simply LocatorDecoration(()=>SomeService()) if type inferrence will do

find

locate<SomeService>() and locateAndBuild<T extends ChangeNotifier>((ctx, t) => yourWidget)

They will be lazily loaded and initialized as requested.

See Example for Simple Usage

Installing

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add dart_board_locator

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  dart_board_locator: ^0.9.9

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:dart_board_locator/dart_board_locator.dart';

Author: Ahammer
Source Code: https://github.com/ahammer/dart_board 
License: BSD-3-Clause license

#flutter #dart #redux 

Dart_board_locator: Redux Extensions for Dart Board
Hans  Marvin

Hans Marvin

1659529740

How to Build A Shopping Cart in React with Redux Toolkit

A shopping cart is essential to every e-commerce site, allowing visitors to select, reserve, and purchase a product or service, and it helps create a frictionless experience for customers.

In this article, we will briefly introduce Redux Toolkit and Redux Persist, what they are, and some of their valuable features. We will learn how they can be used to build a shopping cart in React. To follow along, you should be familiar with React and Hooks and have Node installed on your system.

See more at: https://blog.openreplay.com/building-a-shopping-cart-in-react-with-redux-toolkit-and-redux-persist

#react #reactjs #redux #javascript

How to Build A Shopping Cart in React with Redux Toolkit
Thierry  Perret

Thierry Perret

1659522480

Comment créer un panier dans React & Redux Toolkit

Un panier d'achat est essentiel à chaque site de commerce électronique, permettant aux visiteurs de sélectionner, réserver et acheter un produit ou un service, et il aide à créer une expérience sans friction pour les clients.

Dans cet article, nous présenterons brièvement Redux Toolkit et Redux Persist, ce qu'ils sont et certaines de leurs précieuses fonctionnalités. Nous apprendrons comment ils peuvent être utilisés pour créer un panier d'achat dans React. Pour suivre, vous devez être familiarisé avec React et Hooks et avoir Node installé sur votre système. Tout le code est disponible sur GitHub .

Introduction à la boîte à outils Redux

Redux, à lui seul, est excellent pour la gestion d'état et dispose de nombreux packages qui peuvent être ajoutés pour satisfaire divers cas d'utilisation. Pourtant, un problème courant est la quantité de code passe-partout et de packages nécessaires pour faire quelque chose d'utile, ce que beaucoup jugent inutile. Cela a conduit au développement de Redux Toolkit (RTK) - "l'ensemble d'outils officiel, avisé et avec piles pour un développement efficace de Redux".

Redux Toolkit est la méthode recommandée pour écrire la logique Redux. Il inclut les meilleures pratiques suggérées, simplifie la plupart des tâches Redux, évite les erreurs courantes et facilite l'écriture d'applications Redux. Avec cela vient une option pour démarrer une nouvelle application React avec Redux Toolkit inclus en utilisant la syntaxe de l' application Create React . Avec les commandes suivantes, nous pouvons démarrer une application React ou TypeScript avec Redux Toolkit inclus et une application de contre-exemple pour commencer.

# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript

Après avoir exécuté l'une des commandes ci-dessus, cd dans l'application créée et démarré le serveur de développement avec npm start, nous verrons l'interface suivante dans notre navigateur.

première

Il s'agit d'une application de compteur où nous pouvons augmenter, diminuer et ajouter des nombres de manière asynchrone. Les fichiers critiques utilisés pour cette application sont src/app/features/counter/counterSlice.js, où les réductions, les actions et la logique asynchrone sont créées, et src/app/store.js, où le magasin redux est configuré avec les réducteurs créés. Les fonctions propres à Redux Toolkit utilisées sont createSlice, createAsyncThunket configureStore. Jetons un coup d'œil à eux.

  • createSlice: il s'agit d'une méthode d'assistance qui simplifie le processus de création d'actions et de réducteurs. Il prend le nom de la tranche, de l'état initial et des fonctions du réducteur, renvoie les créateurs d'action à répartir et le réducteur configure le magasin Redux. Cette méthode comprend également un extraReducerschamp pour gérer l'action définie ailleurs, couramment utilisé createAsyncThunkpour écrire de la logique asynchrone. Nous en reparlerons plus createAsyncThunkprochainement. Dans l'application d'exemple de compteur, createSlicea été utilisé pour créer une tranche de compteur avec des réducteurs pour diminuer et augmenter l'état du compteur. Il inclut également des réducteurs supplémentaires pour gérer les actions asynchrones générées par createAsyncThunk.
  • createAsyncThunk: Avec Redux nu, pour effectuer des tâches asynchrones, nous devons d'abord appliquer un middleware comme Redux thunk en utilisant la applyMiddlewarefonction. Mais ce n'est plus le cas pour Redux Toolkit puisque le thunk Redux est inclus par défaut, ce qui nous permet createAsyncThunkd'écrire de la logique asynchrone. La createAsyncThunkméthode accepte une chaîne de type d'action et une fonction de rappel qui renvoie une promesse et génère des types d'action de cycle de vie de promesse en fonction de la chaîne de type d'action transmise, qui peut ensuite être évaluée dans le extraReducerschamp de createSlice. Pour l'application de contre-exemple, nous allons générer trois types d'action : pending : counter/fetchCount/pending; remplie :counter/fetchCount/fulfilled ; et rejeté : counter/fetchCount/rejected. Après avoir passé les paramètres requis àcreateAsyncThunk, il renvoie un créateur d'action thunk qui exécutera le rappel de promesse et distribuera les actions de cycle de vie en fonction de la promesse renvoyée.
  • configureStore: Comme indiqué dans la documentation, [configureStore](https://redux-toolkit.js.org/api/configureStore)wraps [createStore](https://redux.js.org/api/createstore)pour fournir des options de configuration simplifiées et de bonnes valeurs par défaut. Il peut automatiquement combiner nos réducteurs de tranches, ajouter tout middleware Redux que nous fournissons, inclut redux-thunkpar défaut et permet l'utilisation de l'extension Redux DevTools. Cette méthode accepte un seul objet de configuration avec plusieurs propriétés ; le plus important est reducer, un objet qui stocke les réducteurs de tranches, comme on le voit dans l'application de contre-exemple dans src/app/store.js.

Introduction à Redux Persist

Redux Persist est une bibliothèque qui facilite l'enregistrement d'un magasin Redux dans un stockage persistant (par exemple, un stockage local) afin que même après une actualisation du navigateur, l'état soit toujours préservé. Il comprend également des options qui nous permettent de personnaliser l'état persistant et réhydraté.

Pour démarrer avec Redux Persist, nous devons d'abord l'installer, ce qui peut être fait en utilisant l'une des commandes suivantes :

npm i redux-persist
  
// OR
  
yarn add redux-persist

Pour démontrer le fonctionnement de Redux Persist, nous utiliserons le bootstrap d'application de contre-exemple dans la dernière section à l'aide de la npx create-react-app my-app --template reduxcommande. Voici à quoi ressemble la boutique de l'application compteur :

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

Pour conserver le magasin ci-dessus avec la configuration de base et les configurations de Redux Persist, voici à quoi ressemblera le magasin :

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from '../features/counter/counterSlice';
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, counterReducer)

export const store = configureStore({
  reducer: {
    counter: persistedReducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    })
})

export const persistor = persistStore(store)

Les deux fonctions à noter ci-dessus sont persistReduceret persistStore.

  • persistReducerest un réducteur amélioré qui accepte un objet de configuration et le réducteur à persister. L'objet de configuration est utilisé pour spécifier comment persister et réhydrater le réducteur fourni. Dans la configuration ci-dessus utilisant la propriété de stockage, nous avons spécifié que counterReducerl'état doit être conservé dans le stockage local. Outre le stockage local, nous pouvons également utiliser d'autres moteurs de stockage tels que [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
  • persistStoreest la fonction qui fait la persistance et la réhydratation de l'état, et elle prend le magasin Redux comme paramètre. Avec cette fonction, notre magasin sera enregistré dans le stockage local et l'état restera même après une actualisation du navigateur.

Dans la configuration ci-dessus, cofigureStorel'utilisation du middlewarechamp ignore tous les types d'action envoyés par Redux Persist. Ceci est fait pour que nous n'obtenions pas d'erreur dans la lecture de la console du navigateur a non-serializable value was detected in the state.

Pour les cas d'utilisation où nous pourrions vouloir retarder le rendu de notre interface utilisateur jusqu'à ce que les données persistantes soient disponibles dans le magasin Redux. Redux Persist inclut le [PersistGate](https://github.com/ryanwillis/reduxjs-toolkit-persist/blob/main/docs/PersistGate.md)composant. Pour utiliser PersistGate, index.jsajoutez les importations suivantes :

import { persistor, store } from './app/store';
import { PersistGate } from 'redux-persist/integration/react';

Maintenant, modifiez la renderméthode pour qu'elle ressemble à ceci :

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={<Loader />} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

C'est tout ce dont nous avons besoin pour démarrer avec Redux Persist. Pour des personnalisations et des configurations spécifiques pour d'autres cas d'utilisation, vous pouvez consulter State Reconciler , Blacklist & Whitelist et Nested Persists , et Transforms .

Nous avons maintenant compris comment fonctionnent Redux Toolkit et Redux Persist. Voyons comment les combiner pour construire quelque chose d'utile.

Construire un panier avec Redux Toolkit et Redux Persist

J'ai déjà créé un référentiel de démarrage avec un modèle que nous utiliserons pour créer le panier afin que nous puissions nous concentrer uniquement sur la mise en œuvre.

L'étape suivante consiste à cloner le référentiel GitHub et à installer les dépendances nécessaires. Nous pouvons le faire avec les commandes suivantes :

git clone -b starter https://github.com/Tammibriggs/shopping-cart.git

cd shopping-cart

npm install @reduxjs/toolkit react-redux redux-persist

Dans le modèle de démarrage, j'ai inclus une page d'accueil où les articles sont affichés et une page Panier pour afficher les articles ajoutés au panier. Après avoir démarré l'application clonée avec la npm startcommande, nous verrons l'accueil dans notre navigateur :

2

Pour naviguer dans la page Panier, cliquez sur l'icône du panier située en bas à droite de la page, et nous verrons l'écran suivant :

3

Maintenant que nous avons un modèle, commençons par la mise en œuvre. Tout d'abord, nous allons utiliser la createSliceméthode pour créer une tranche avec des réducteurs pour effectuer les opérations suivantes :

  • Ajouter un article au panier
  • Augmenter la quantité d'un article dans le panier
  • Diminuer la quantité d'un article dans le panier
  • Supprimer un article du panier

Ce sont les actions associées à la mise en place d'un panier. Pour créer la tranche, dans le srcrépertoire de l'application clone, créez d'abord un reduxdossier. C'est là que nous voulons mettre les fichiers liés à la gestion de l'état. Maintenant, dans ce dossier, créez un cartSlice.jsfichier et ajoutez les lignes de code suivantes :

// src/redux/cartSlice.js
import { createSlice } from '@reduxjs/toolkit';

const cartSlice = createSlice({
  name: 'cart',
  initialState: {
    cart: [],
  },
  reducers: {
    addToCart: (state, action) => {
      const itemInCart = state.cart.find((item) => item.id === action.payload.id);
      if (itemInCart) {
        itemInCart.quantity++;
      } else {
        state.cart.push({ ...action.payload, quantity: 1 });
      }
    },
    incrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      item.quantity++;
    },
    decrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      if (item.quantity === 1) {
        item.quantity = 1
      } else {
        item.quantity--;
      }
    },
    removeItem: (state, action) => {
      const removeItem = state.cart.filter((item) => item.id !== action.payload);
      state.cart = removeItem;
    },
  },
});

export const cartReducer = cartSlice.reducer;
export const {
  addToCart,
  incrementQuantity,
  decrementQuantity,
  removeItem,
} = cartSlice.actions;

Dans le code ci-dessus, nous avons créé une tranche de panier avec les réducteurs suivants :

  • addToCart: Reçoit l'objet d'élément à ajouter à l'état en tant que charge utile. Pour ajouter l'élément, nous vérifions d'abord s'il existe déjà en utilisant la findméthode ; si c'est le cas, nous incrémentons sa quantité, mais sinon, nous l'ajoutons à l'état en utilisant la pushméthode.
  • incrementQuantity: Reçoit un ID d'article en tant que charge utile, utilisé pour trouver l'article dans l'état à l'aide de la findméthode, puis incrémente sa quantité de 1.
  • decrementQuantity : Ce réducteur reçoit un ID d'élément en tant que charge utile. À l'aide de l'ID, nous trouvons et décrémentons la quantité d'articles dans l'état uniquement lorsque sa quantité est supérieure à 1.
  • removeItem: Reçoit l'ID d'élément en tant que charge utile qui est ensuite utilisée pour supprimer de l'état à l'aide de la filterméthode.

Maintenant, en utilisant le réducteur exporté et les créateurs d'action dans le code ci-dessus, configurons le magasin redux et commençons à répartir les actions pour la fonctionnalité de panier d'achat. Dans le reduxdossier, créez un store.jsfichier et ajoutez-y la ligne de code suivante :

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";

export const store = configureStore({
  reducer: cartReducer
})

Maintenant, enveloppons nos composants avec <Provider>from react-redux, qui prend notre magasin Redux comme accessoire afin que tous les composants de notre application puissent accéder et utiliser l'état global. Dans le index.jsfichier, ajoutez d'abord les importations suivantes :

// src/index.js
import { Provider } from 'react-redux';
import { store } from './redux/store';

Maintenant, modifiez la renderfonction pour qu'elle ressemble à ceci :

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

Nous avons maintenant terminé la configuration et nous pouvons commencer à interagir avec notre magasin en utilisant les crochets React-Redux. Pour lire les données du magasin, nous utiliserons le useSelectorcrochet, et pour envoyer des actions, nous utiliserons le useDispatchcrochet.

Ajout d'articles au panier

Nous pouvons ajouter un article au panier en appelant le addToCartcréateur de l'action dans la fonction dispatch de useDispatch, en transmettant l'objet article à ajouter en tant que paramètre.

Dans la page d'accueil de notre application, lorsque le Add to Cartbouton d'un article est cliqué, nous voulons que cet article soit ajouté au panier. Pour ce faire, rendez-vous sur src/components/Item.jset ajoutez d'abord les importations suivantes :

// src/components/Item.js
import { useDispatch } from 'react-redux';
import {addToCart} from '../redux/cartSlice';

Ensuite, ajoutez la ligne de code suivante dans le Itemcomposant avant l' returninstruction.

// src/components/Item.js
const dispatch = useDispatch()

Maintenant, dans l' returninstruction, modifiez le Add to Cartbouton pour qu'il ressemble à ceci :

// src/components/Item.js
<button 
  onClick={() => 
    dispatch(addToCart({
      id, title, image, price
    }))
  }>Add to Cart
</button>

Avec cela, lorsque nous cliquons sur le Add to Cartbouton de n'importe quel article de notre application, cet article sera ajouté au panier. Pour ajouter une indication de cela dans l'interface utilisateur, nous devons augmenter le nombre dans l'icône du panier en bas à droite de notre application.

Rendez-vous sur src/pages/Home.jset ajoutez d'abord l'importation suivante :

// src/pages/Home.js
import { useSelector } from 'react-redux';

Ensuite, ajoutez les lignes de code suivantes après le useNavigatecrochet dans le Homecomposant :

// src/pages/Home.js
const cart = useSelector((state) => state.cart)

const getTotalQuantity = () => {
  let total = 0
  cart.forEach(item => {
    total += item.quantity
  })
  return total
}

Dans le code ci-dessus, nous avons utilisé le useSelectorcrochet pour obtenir l'état du panier de notre magasin Redux. Ensuite, nous avons créé une getTotalQuantityfonction qui renvoie la quantité totale d'articles dans le magasin. Maintenant, pour utiliser cette fonction, modifiez le divavec le classNamede shopping-cartpour qu'il ressemble à ceci :

// src/pages/Home.js
<div className='shopping-cart' onClick={() => navigate('/cart')}>
  <ShoppingCart id='cartIcon'/>
  <p>{getTotalQuantity() || 0}</p>
</div>

Avec cela, il y aura une indication dans l'interface indiquant combien de quantités d'articles ont été ajoutées au panier.

4

Affichage des articles ajoutés au magasin sur la page Panier

Même après avoir ajouté des articles à notre magasin, il sera toujours vide lorsque nous irons à la page Panier en cliquant sur l'icône du panier en bas à droite.

Pour afficher les articles, nous utiliserons le useSelectorcrochet pour obtenir l'état du panier de notre magasin, puis le cartographierons.

Rendez-vous sur src/pages/Cart.jset ajoutez d'abord l'importation suivante :

// src/pages/Cart.js
import { useSelector } from 'react-redux'

Ensuite, ajoutez la ligne de code suivante dans le Cartcomposant avant l' returninstruction :

// src/pages/Cart.js
const cart = useSelector((state) => state.cart)

Ensuite, modifiez le divavec un classNameof cart__leftpour qu'il ressemble à ceci :

// src/pages/Cart.js
<div className="cart__left">
  <div>
    <h3>Shopping Cart</h3>
    {cart?.map((item) => (
      <CartItem
        key={item.id}
        id={item.id}
        image={item.image}
        title={item.title}
        price={item.price} 
        quantity={item.quantity}
      />
    ))}
  </div>
</div>

Avec cela, les articles ajoutés dans le magasin seront affichés sur l'interface.

Ajout de fonctionnalités de gestion de panier

Ajoutons les fonctionnalités pour augmenter et diminuer la quantité d'un article dans le panier et le retirer du panier. Nous avons déjà créé les réducteurs pour les gérer, nous devons donc maintenant envoyer les actions correspondantes.

Pour ce faire, dirigez-vous vers src/components/CartItem.jset modifiez l'intégralité du fichier pour qu'il ressemble maintenant à ceci :

// src/components/CartItem.js
import './cartItem.css'
import { incrementQuantity, decrementQuantity, removeItem} from '../redux/cartSlice'
import { useDispatch } from 'react-redux'

function CartItem({id, image, title, price, quantity=0}) {
  const dispatch = useDispatch()

  return (
    <div className="cartItem">
      <img className="cartItem__image" src={image} alt='item'/>
      <div className="cartItem__info">
        <p className="cartItem__title">{title}</p>
        <p className="cartItem__price">
          <small>$</small>
          <strong>{price}</strong>
        </p>
        <div className='cartItem__incrDec'>
          <button onClick={() => dispatch(decrementQuantity(id))}>-</button>
          <p>{quantity}</p>
          <button onClick={() => dispatch(incrementQuantity(id))}>+</button>
        </div>
        <button
          className='cartItem__removeButton' 
          onClick={() => dispatch(removeItem(id))}>
            Remove
        </button>
      </div>
    </div>
  )
}

export default CartItem

Dans le code ci-dessus, nous avons importé des créateurs d'action , , et les avons appelés dans la incrementQuantityfonction decrementQuantity, en leur transmettant l'ID de l'élément. Les fonctions de répartition sont appelées dans le gestionnaire d'événements des boutons correspondant aux créateurs d'action.removeItemdispatchonClick

Avec cela, lorsque nous allons sur la page du panier et que nous cliquons sur l'un des boutons de gestion d'un article, leurs actions correspondantes seront envoyées et l'état sera mis à jour.

Maintenant, il ne reste plus qu'à afficher le prix total et le nombre d'articles dans le panier. Pour ce faire, dirigez-vous src/components/Total.jset ajoutez d'abord l'importation suivante :

// src/components/Total.js
import {useSelector} from 'react-redux'

Ensuite, ajoutez les lignes de code suivantes dans le Totalcomposant avant l' returninstruction :

// src/components/Total.js
const cart = useSelector((state) => state.cart)

const getTotal = () => {
  let totalQuantity = 0
  let totalPrice = 0
  cart.forEach(item => {
    totalQuantity += item.quantity
    totalPrice += item.price * item.quantity
  })
  return {totalPrice, totalQuantity}
}

Dans le code ci-dessus, nous avons obtenu l'état du panier du magasin Redux, puis créé une getTotalfonction qui renvoie le prix total et la quantité de l'article dans le panier. Maintenant, pour l'utiliser, modifiez le divavec le classNamede total__ppour qu'il ressemble à ceci :

// src/components/Total.js
<p className="total__p">
  total ({getTotal().totalQuantity} items) 
  : <strong>${getTotal().totalPrice}</strong>
</p>

Après avoir ajouté des articles au panier, nous devrions voir le prix total et la quantité sur la page Panier.

5

État du panier persistant avec Redux Persist

À l'heure actuelle, après avoir ajouté des éléments dans l'état du panier, même une actualisation du navigateur effacera le magasin Redux, ce qui entraînera la perte de nos données, ce qui n'est pas une bonne implémentation d'un panier. Donc, pour persister dans le magasin dans le stockage local et se réhydrater lorsque l'application se charge à nouveau, nous utiliserons Redux Persist, que nous avons couvert ci-dessus.

Rendez-vous sur src/redux/store.jset modifiez le fichier pour qu'il ressemble à ceci :

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, cartReducer)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})

export const persistor = persistStore(store)

Avec cela, nous avons ajouté de la persistance pour notre magasin Redux, et nous avons fini de construire notre panier.

Conclusion

Un panier d'achat est un élément essentiel de chaque application de commerce électronique. Le construire avec les bons outils comme ce tutoriel rend sa mise en œuvre plus simple et plus simple. Dans ce didacticiel, nous avons appris à créer un panier avec Redux Toolkit et Redux Persist. Avec cela, vous devriez pouvoir l'ajouter facilement à votre application.

#react #reactjs #redux #javascript

Comment créer un panier dans React & Redux Toolkit

What Are The Differences Between Redux-saga and Redux-thunk ?

In this brief guide, We will share What Are The Differences Between Redux-saga and Redux-thunk ?

redux-saga is a library that aims to make side effects (asynchronous things like data fetching and impure things like accessing the browser cache) in React/Redux applications easier and better.

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch() and getState() as parameters.

Both Redux Thunk and Redux Saga take care of dealing with side effects. In most of the scenarios, Thunk uses Promises to deal with them, whereas Saga uses Generators. Thunk is simple to use and Promises are familiar to many developers, Sagas/Generators are more powerful but you will need to learn them. But both middleware can coexist, so you can start with Thunks and introduce Sagas when/if you need them.

Link: https://github.com/sudheerj/reactjs-interview-questions

#react #reactjs #javascript #redux

What Are The Differences Between Redux-saga and Redux-thunk ?

Как создать корзину в React с помощью Redux Toolkit

Корзина необходима для каждого сайта электронной коммерции, позволяя посетителям выбирать, резервировать и приобретать продукт или услугу, а также помогает создать беспроблемный опыт для клиентов.

В этой статье мы кратко расскажем о Redux Toolkit и Redux Persist, о том, что они из себя представляют, и о некоторых их ценных функциях. Мы узнаем, как их можно использовать для создания корзины покупок в React. Чтобы продолжить, вы должны быть знакомы с React и Hooks и иметь установленный Node в вашей системе. Весь код доступен на GitHub .

Введение в набор инструментов Redux

Redux сам по себе отлично подходит для управления состоянием и имеет множество пакетов, которые можно добавлять для различных вариантов использования. Тем не менее, распространенной проблемой является количество шаблонного кода и пакетов, необходимых для выполнения чего-то полезного, что многие считают ненужным. Это привело к разработке Redux Toolkit (RTK) — «официального, самоуверенного набора инструментов с батарейным питанием для эффективной разработки Redux».

Redux Toolkit — рекомендуемый способ написания логики Redux. Он включает в себя рекомендуемые передовые практики, упрощает большинство задач Redux, предотвращает распространенные ошибки и упрощает написание приложений Redux. С ним появляется возможность запустить новое приложение React с включенным Redux Toolkit, используя синтаксис приложения Create React . С помощью следующих команд мы можем запустить приложение React или TypeScript с включенным Redux Toolkit и приложением-контрпримером для начала.

# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript

После запуска одной из приведенных выше команд, перейдите в созданное приложение и запустите сервер разработки с помощью npm start, мы увидим следующий интерфейс в нашем браузере.

первый

Это приложение-счетчик, в котором мы можем увеличивать, уменьшать и асинхронно добавлять числа. Важными файлами, используемыми для этого приложения, являются src/app/features/counter/counterSlice.js, где создаются сокращения, действия и асинхронная логика, и src/app/store.js, где хранилище избыточности настраивается с помощью созданных уменьшений. Используемые функции Redux Toolkit: createSlice, createAsyncThunkи configureStore. Давайте посмотрим на них.

  • createSlice: это вспомогательный метод, упрощающий процесс создания действий и редюсеров. Он принимает имя слайса, начальное состояние и функции редуктора, возвращает создателей действий для отправки, а редьюсер настраивает хранилище Redux. Этот метод также включает extraReducersполе для обработки действия, определенного в другом месте, которое обычно используется createAsyncThunkдля написания асинхронной логики. Мы поговорим подробнее в createAsyncThunkближайшее время. В примере приложения со счетчиком createSliceон использовался для создания среза счетчика с редюсерами для уменьшения и увеличения состояния счетчика. Он также включает дополнительные редукторы для обработки асинхронных действий, генерируемых createAsyncThunk.
  • createAsyncThunk: С голым Redux для выполнения асинхронных задач нам сначала нужно применить промежуточное программное обеспечение, такое как преобразователь Redux , с помощью applyMiddlewareфункции. Но это больше не относится к Redux Toolkit, поскольку преобразователь Redux включен по умолчанию, что позволяет нам использовать createAsyncThunkего для написания асинхронной логики. Метод createAsyncThunkпринимает строку типа действия и функцию обратного вызова, которая возвращает обещание и создает типы действий жизненного цикла обещания на основе переданной строки типа действия, которую затем можно оценить в extraReducersполе createSlice. Для приложения-контрпримера мы создадим три типа действий: pending: counter/fetchCount/pending; выполнено: counter/fetchCount/fulfilled; и отклонено: counter/fetchCount/rejected. После передачи необходимых параметров вcreateAsyncThunk, он возвращает создателя действия thunk, который запустит обратный вызов обещания и отправит действия жизненного цикла на основе возвращенного обещания.
  • configureStore: Как указано в документах, [configureStore](https://redux-toolkit.js.org/api/configureStore)обертки [createStore](https://redux.js.org/api/createstore)обеспечивают упрощенные параметры конфигурации и хорошие значения по умолчанию. Он может автоматически комбинировать наши редукторы слайсов, добавлять любое промежуточное ПО Redux, которое мы поставляем, включает redux-thunkпо умолчанию и позволяет использовать расширение Redux DevTools Extension. Этот метод принимает один объект конфигурации с несколькими свойствами; наиболее важным является reducerобъект, в котором хранятся редукторы слайсов, как показано в приложении-контрпримере в src/app/store.js.

Введение в Redux Persist

Redux Persist — это библиотека, упрощающая сохранение хранилища Redux в постоянном хранилище (например, в локальном хранилище), так что даже после обновления браузера состояние сохраняется. Он также включает параметры, которые позволяют нам настраивать состояние, которое сохраняется и регидратируется.

Чтобы начать работу с Redux Persist, нам нужно сначала установить его, что можно сделать с помощью одной из следующих команд:

npm i redux-persist
  
// OR
  
yarn add redux-persist

Чтобы продемонстрировать, как работает Redux Persist, мы будем использовать загрузочную загрузку приложения контрпримера в последнем разделе с помощью npx create-react-app my-app --template reduxкоманды. Вот как выглядит магазин приложения-счетчика:

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

Чтобы сохранить вышеуказанный магазин с базовой настройкой и конфигурациями Redux Persist, вот как будет выглядеть магазин:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from '../features/counter/counterSlice';
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, counterReducer)

export const store = configureStore({
  reducer: {
    counter: persistedReducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    })
})

export const persistor = persistStore(store)

Две функции, которые следует отметить выше, — это persistReducerи persistStore.

  • persistReducer— это расширенный редуктор, который принимает объект конфигурации и редуктор для сохранения. Объект конфигурации используется для указания того, как сохранять и регидратировать предоставленный редюсер. В приведенной выше конфигурации с использованием свойства хранилища мы указали, что counterReducerсостояние должно сохраняться в локальном хранилище. Помимо локального хранилища, мы также можем использовать другие механизмы хранения, такие как [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
  • persistStore— это функция, которая сохраняет и регидратирует состояние, и принимает хранилище Redux в качестве параметра. С помощью этой функции наш магазин будет сохранен в локальном хранилище, а состояние останется даже после обновления браузера.

В приведенной выше настройке при cofigureStoreиспользовании middlewareполя игнорируются все типы действий, отправляемые Redux Persist. Это сделано для того, чтобы мы не получили ошибку при чтении консоли браузера a non-serializable value was detected in the state.

Для случаев использования, когда мы можем захотеть отложить рендеринг нашего пользовательского интерфейса, пока сохраненные данные не будут доступны в магазине Redux. Redux Persist включает [PersistGate](https://github.com/ryanwillis/reduxjs-toolkit-persist/blob/main/docs/PersistGate.md)компонент. Чтобы использовать PersistGate, index.jsдобавьте следующие импорты:

import { persistor, store } from './app/store';
import { PersistGate } from 'redux-persist/integration/react';

Теперь измените renderметод, чтобы он выглядел так:

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={<Loader />} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

Это все, что нам нужно для начала работы с Redux Persist. Для конкретных настроек и конфигураций для других случаев использования вы можете проверить State Reconciler , Blacklist & Whitelist , Nested Persists и Transforms .

Теперь мы поняли, как работают Redux Toolkit и Redux Persist. Давайте посмотрим, как объединить их, чтобы построить что-то полезное.

Создайте корзину с помощью Redux Toolkit и Redux Persist

Я уже создал начальный репозиторий с шаблоном, который мы будем использовать для создания корзины покупок, чтобы мы могли сосредоточиться исключительно на реализации.

Следующим шагом будет клонирование репозитория GitHub и установка необходимых зависимостей. Мы можем сделать это с помощью следующих команд:

git clone -b starter https://github.com/Tammibriggs/shopping-cart.git

cd shopping-cart

npm install @reduxjs/toolkit react-redux redux-persist

В начальный шаблон я включил домашнюю страницу, на которой отображаются товары, и страницу корзины для просмотра товаров, добавленных в корзину. После запуска клонированного приложения с помощью npm startкоманды мы увидим Дом в нашем браузере:

2

Чтобы перейти на страницу «Корзина», щелкните значок корзины, расположенный в правом нижнем углу страницы, и мы увидим следующий экран:

3

Теперь, когда у нас есть шаблон, давайте начнем с реализации. Во-первых, мы будем использовать createSliceметод для создания слайса с редюсерами для выполнения следующих действий:

  • Добавление товара в корзину
  • Увеличение количества товара в корзине
  • Уменьшение количества товара в корзине
  • Удаление товара из корзины

Это действия, связанные с реализацией корзины. Чтобы создать фрагмент, сначала создайте папку в каталоге srcприложения-клона . reduxСюда мы хотим поместить файлы, связанные с управлением состоянием. Теперь в этой папке создайте cartSlice.jsфайл и добавьте следующие строки кода:

// src/redux/cartSlice.js
import { createSlice } from '@reduxjs/toolkit';

const cartSlice = createSlice({
  name: 'cart',
  initialState: {
    cart: [],
  },
  reducers: {
    addToCart: (state, action) => {
      const itemInCart = state.cart.find((item) => item.id === action.payload.id);
      if (itemInCart) {
        itemInCart.quantity++;
      } else {
        state.cart.push({ ...action.payload, quantity: 1 });
      }
    },
    incrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      item.quantity++;
    },
    decrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      if (item.quantity === 1) {
        item.quantity = 1
      } else {
        item.quantity--;
      }
    },
    removeItem: (state, action) => {
      const removeItem = state.cart.filter((item) => item.id !== action.payload);
      state.cart = removeItem;
    },
  },
});

export const cartReducer = cartSlice.reducer;
export const {
  addToCart,
  incrementQuantity,
  decrementQuantity,
  removeItem,
} = cartSlice.actions;

В приведенном выше коде мы создали слайс корзины со следующими редюсерами:

  • addToCart: получает объект элемента для добавления в состояние в качестве полезной нагрузки. Чтобы добавить элемент, мы сначала проверяем, существует ли он уже с помощью findметода; если да, то увеличиваем его количество, а если нет, то добавляем в состояние с помощью pushметода.
  • incrementQuantity: получает идентификатор элемента в качестве полезной нагрузки, используемый для поиска элемента в состоянии с помощью findметода, а затем увеличивает его количество на 1.
  • decrementQuantity: этот редьюсер получает идентификатор элемента в качестве полезной нагрузки. По ID находим и уменьшаем количество товара в состоянии только тогда, когда его количество больше 1.
  • removeItem: получает идентификатор элемента в качестве полезной нагрузки, которая затем используется для удаления из состояния с помощью filterметода.

Теперь, используя экспортированный редюсер и создателей действий в приведенном выше коде, давайте настроим хранилище избыточности и начнем отправлять действия для функциональности корзины покупок. В reduxпапке создайте store.jsфайл и добавьте в него следующую строку кода:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";

export const store = configureStore({
  reducer: cartReducer
})

Теперь давайте обернем наши компоненты <Provider>from react-redux, который использует наше хранилище Redux в качестве реквизита, чтобы все компоненты в нашем приложении могли получать доступ и использовать глобальное состояние. Сначала в index.jsфайле добавьте следующие импорты:

// src/index.js
import { Provider } from 'react-redux';
import { store } from './redux/store';

Теперь измените renderфункцию, чтобы она выглядела следующим образом:

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

Теперь мы закончили настройку и можем начать взаимодействовать с нашим магазином, используя хуки React-Redux. Для чтения данных из хранилища мы будем использовать useSelectorхук, а для отправки действий мы будем использовать useDispatchхук.

Добавление товаров в корзину

Мы можем добавить товар в корзину, вызвав addToCartсоздателя действия в функции отправки из useDispatch, передав объект товара, который нужно добавить, в качестве параметра.

На домашней странице нашего приложения при Add to Cartнажатии кнопки элемента мы хотим, чтобы этот элемент был добавлен в корзину. Для этого перейдите src/components/Item.jsи сначала добавьте следующие импорты:

// src/components/Item.js
import { useDispatch } from 'react-redux';
import {addToCart} from '../redux/cartSlice';

Затем добавьте следующую строку кода в Itemкомпонент перед returnоператором.

// src/components/Item.js
const dispatch = useDispatch()

Теперь в returnоператоре измените Add to Cartкнопку, чтобы она выглядела следующим образом:

// src/components/Item.js
<button 
  onClick={() => 
    dispatch(addToCart({
      id, title, image, price
    }))
  }>Add to Cart
</button>

При этом, когда мы нажимаем Add to Cartкнопку на любом элементе в нашем приложении, этот элемент будет добавлен в корзину. Чтобы добавить индикацию этого в пользовательский интерфейс, мы должны увеличить число на значке корзины покупок в правом нижнем углу нашего приложения.

Перейдите src/pages/Home.jsи сначала добавьте следующий импорт:

// src/pages/Home.js
import { useSelector } from 'react-redux';

Затем добавьте следующие строки кода после useNavigateхука в Homeкомпоненте:

// src/pages/Home.js
const cart = useSelector((state) => state.cart)

const getTotalQuantity = () => {
  let total = 0
  cart.forEach(item => {
    total += item.quantity
  })
  return total
}

В приведенном выше коде мы использовали useSelectorхук для получения состояния корзины из нашего магазина Redux. Затем мы создали getTotalQuantityфункцию, которая возвращает общее количество товаров в магазине. Теперь, чтобы использовать эту функцию, измените divс помощью classNameof shopping-cart, чтобы она выглядела следующим образом:

// src/pages/Home.js
<div className='shopping-cart' onClick={() => navigate('/cart')}>
  <ShoppingCart id='cartIcon'/>
  <p>{getTotalQuantity() || 0}</p>
</div>

При этом в интерфейсе будет отображаться количество товаров, добавленных в корзину.

4

Отображение товаров, добавленных в магазин, на странице корзины

Даже после добавления товаров в наш магазин он все равно будет пустым, когда мы перейдем на страницу корзины, щелкнув значок корзины в правом нижнем углу.

Чтобы отобразить товары, мы будем использовать useSelectorхук, чтобы получить состояние корзины из нашего магазина, а затем сопоставить его.

Перейдите src/pages/Cart.jsи сначала добавьте следующий импорт:

// src/pages/Cart.js
import { useSelector } from 'react-redux'

Затем добавьте следующую строку кода в Cartкомпонент перед returnоператором:

// src/pages/Cart.js
const cart = useSelector((state) => state.cart)

Затем измените divс помощью classNameof cart__left, чтобы он выглядел следующим образом:

// src/pages/Cart.js
<div className="cart__left">
  <div>
    <h3>Shopping Cart</h3>
    {cart?.map((item) => (
      <CartItem
        key={item.id}
        id={item.id}
        image={item.image}
        title={item.title}
        price={item.price} 
        quantity={item.quantity}
      />
    ))}
  </div>
</div>

При этом добавленные предметы в магазине будут отображаться в интерфейсе.

Добавление функций управления корзиной

Давайте добавим функциональные возможности для увеличения и уменьшения количества товара в корзине и удаления его из корзины. Мы уже создали редьюсеры для их обработки, поэтому теперь нам нужно отправить соответствующие действия.

Для этого src/components/CartItem.jsперейдите и измените весь файл, чтобы он выглядел следующим образом:

// src/components/CartItem.js
import './cartItem.css'
import { incrementQuantity, decrementQuantity, removeItem} from '../redux/cartSlice'
import { useDispatch } from 'react-redux'

function CartItem({id, image, title, price, quantity=0}) {
  const dispatch = useDispatch()

  return (
    <div className="cartItem">
      <img className="cartItem__image" src={image} alt='item'/>
      <div className="cartItem__info">
        <p className="cartItem__title">{title}</p>
        <p className="cartItem__price">
          <small>$</small>
          <strong>{price}</strong>
        </p>
        <div className='cartItem__incrDec'>
          <button onClick={() => dispatch(decrementQuantity(id))}>-</button>
          <p>{quantity}</p>
          <button onClick={() => dispatch(incrementQuantity(id))}>+</button>
        </div>
        <button
          className='cartItem__removeButton' 
          onClick={() => dispatch(removeItem(id))}>
            Remove
        </button>
      </div>
    </div>
  )
}

export default CartItem

В приведенном выше коде мы импортировали incrementQuantity, decrementQuantity, removeItemсоздателей действий и вызвали их в dispatchфункции, передав им идентификатор элемента. Функции диспетчеризации вызываются в onClickобработчике событий кнопок, соответствующих создателям действий.

При этом, когда мы переходим на страницу «Корзина» и нажимаем любую из кнопок для управления товаром, будут отправлены соответствующие действия, а состояние будет обновлено.

Теперь осталось отобразить общую цену и количество товаров в корзине. Для этого перейдите src/components/Total.jsи сначала добавьте следующий импорт:

// src/components/Total.js
import {useSelector} from 'react-redux'

Затем добавьте следующие строки кода в Totalкомпонент перед returnоператором:

// src/components/Total.js
const cart = useSelector((state) => state.cart)

const getTotal = () => {
  let totalQuantity = 0
  let totalPrice = 0
  cart.forEach(item => {
    totalQuantity += item.quantity
    totalPrice += item.price * item.quantity
  })
  return {totalPrice, totalQuantity}
}

В приведенном выше коде мы получили состояние корзины из магазина Redux, а затем создали getTotalфункцию, которая возвращает общую цену и количество товара в корзине. Теперь, чтобы использовать это, измените the divwith the classNameof total__p, чтобы он выглядел так:

// src/components/Total.js
<p className="total__p">
  total ({getTotal().totalQuantity} items) 
  : <strong>${getTotal().totalPrice}</strong>
</p>

После добавления товаров в корзину мы должны увидеть общую цену и количество на странице корзины.

5

Сохранение состояния корзины с помощью Redux Persist

Прямо сейчас, после добавления элементов в состояние корзины, даже обновление браузера очистит магазин Redux, что приведет к потере наших данных, что не является хорошей реализацией корзины покупок. Таким образом, чтобы сохранить хранилище в локальном хранилище и восстановить его при повторной загрузке приложения, мы будем использовать Redux Persist, о котором мы говорили выше.

Перейдите к src/redux/store.jsи измените файл, чтобы он выглядел следующим образом:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, cartReducer)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})

export const persistor = persistStore(store)

Благодаря этому мы добавили постоянство для нашего магазина Redux, и мы закончили создание нашей корзины покупок.

Вывод

Корзина является неотъемлемой частью любого приложения электронной коммерции. Создание его с помощью правильных инструментов, таких как этот учебник, делает его реализацию проще и понятнее. В этом уроке мы узнали, как создать корзину для покупок с помощью Redux Toolkit и Redux Persist. Благодаря этому вы сможете легко добавить его в свое приложение.

#react #reactjs #redux #javascript

Как создать корзину в React с помощью Redux Toolkit

What Are The Differences Between Call() and Put() in Redux-saga ?

In this brief guide, We will share What Are The Differences Between Call() and Put() in Redux-saga.

Both call() and put() are effect creator functions. call() function is used to create effect description, which instructs middleware to call the promise. put() function creates an effect, which instructs middleware to dispatch an action to the store.

Let's take example of how these effects work for fetching particular user data.

function* fetchUserSaga(action) {
  // `call` function accepts rest arguments, which will be passed to `api.fetchUser` function.
  // Instructing middleware to call promise, it resolved value will be assigned to `userData` variable
  const userData = yield call(api.fetchUser, action.userId)

  // Instructing middleware to dispatch corresponding action.
  yield put({
    type: 'FETCH_USER_SUCCESS',
    userData
  })
}

Link: https://github.com/sudheerj/reactjs-interview-questions

#react #reactjs #javascript #redux

What Are The Differences Between Call() and Put() in Redux-saga ?
Hoang  Kim

Hoang Kim

1659507905

Cách Tạo Giỏ Hàng Trong React Với Bộ Công Cụ Redux

Giỏ hàng là điều cần thiết đối với mọi trang web thương mại điện tử, cho phép khách truy cập chọn, đặt trước và mua sản phẩm hoặc dịch vụ, đồng thời giúp tạo ra trải nghiệm dễ dàng cho khách hàng.

Trong bài viết này, chúng tôi sẽ giới thiệu ngắn gọn về Redux Toolkit và Redux Persist, chúng là gì và một số tính năng có giá trị của chúng. Chúng ta sẽ tìm hiểu cách chúng có thể được sử dụng để tạo giỏ hàng trong React. Để làm theo, bạn nên làm quen với React và Hooks và đã cài đặt Node trên hệ thống của mình. Tất cả mã đều có trên GitHub .

Giới thiệu về Bộ công cụ Redux

Redux, về bản thân, rất tuyệt vời cho việc quản lý trạng thái và có rất nhiều gói có thể được thêm vào để đáp ứng các trường hợp sử dụng khác nhau. Tuy nhiên, một vấn đề phổ biến là số lượng mã soạn sẵn và các gói cần thiết để làm điều gì đó hữu ích, mà nhiều người cảm thấy là không cần thiết. Điều này dẫn đến sự phát triển của Bộ công cụ Redux (RTK) - “bộ công cụ chính thức, có ý kiến, có pin để phát triển Redux hiệu quả”.

Redux Toolkit là cách viết logic của Redux được khuyến nghị. Nó bao gồm các phương pháp hay nhất được đề xuất, đơn giản hóa hầu hết các tác vụ Redux, ngăn ngừa các lỗi thường gặp và giúp viết ứng dụng Redux dễ dàng hơn. Đi kèm với nó là một tùy chọn để bắt đầu một ứng dụng React mới với Bộ công cụ Redux đi kèm bằng cách sử dụng cú pháp Tạo ứng dụng React . Với các lệnh sau, chúng ta có thể khởi động ứng dụng React hoặc TypeScript với Bộ công cụ Redux đi kèm và một ứng dụng ví dụ ngược lại để bắt đầu.

# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript

Sau khi chạy một trong các lệnh trên, cd vào ứng dụng đã tạo và khởi động máy chủ phát triển bằng npm start, chúng ta sẽ thấy giao diện sau trong trình duyệt của mình.

1

Đây là một ứng dụng bộ đếm nơi chúng tôi có thể tăng, giảm và thêm số không đồng bộ. Các tệp quan trọng được sử dụng cho ứng dụng này là src/app/features/counter/counterSlice.jsnơi tạo giảm bớt, hành động và logic không đồng bộ và src/app/store.jsnơi lưu trữ redux được định cấu hình với các trình giảm đã tạo. Chức năng đặc biệt của Bộ công cụ Redux được sử dụng là createSlice, createAsyncThunkconfigureStore. Chúng ta hãy nhìn vào chúng.

  • createSlice: đây là một phương thức trợ giúp đơn giản hóa quá trình tạo các hành động và bộ giảm bớt. Nó lấy tên của slice, trạng thái ban đầu và các chức năng của bộ giảm, trả về trình tạo hành động sẽ được gửi đi và bộ giảm cấu hình cửa hàng Redux. Phương thức này cũng bao gồm một extraReducerstrường để xử lý hành động được xác định ở nơi khác, thường được sử dụng createAsyncThunkđể viết logic không đồng bộ. Chúng tôi sẽ nói nhiều hơn về nó createAsyncThunkngay sau đây. Trong ứng dụng ví dụ bộ đếm, createSliceđược sử dụng để tạo một lát bộ đếm với các bộ giảm để giảm và tăng trạng thái bộ đếm. Nó cũng bao gồm các bộ giảm bổ sung để xử lý hành động không đồng bộ được tạo bởi createAsyncThunk.
  • createAsyncThunk: Với Redux trần, để thực hiện các tác vụ không đồng bộ, trước tiên chúng ta cần áp dụng một phần mềm trung gian như Redux thunk bằng cách sử dụng applyMiddlewarehàm. Nhưng điều này không còn đúng với Redux Toolkit vì Redux thunk được bao gồm theo mặc định, cho phép chúng ta sử dụng createAsyncThunkđể viết logic không đồng bộ. Phương createAsyncThunkthức chấp nhận một chuỗi kiểu hành động và một hàm gọi lại trả về một lời hứa và tạo ra các kiểu hành động trong vòng đời của lời hứa dựa trên chuỗi kiểu hành động được truyền vào, sau đó có thể được đánh giá trong extraReducerstrường của createSlice. Đối với ứng dụng ví dụ phản hồi, chúng tôi sẽ tạo ba loại hành động: đang chờ xử lý counter/fetchCount/pending:; hoàn thành counter/fetchCount/fulfilled:; counter/fetchCount/rejectedvà bị từ chối:. Sau khi chuyển các tham số bắt buộc đếncreateAsyncThunk, nó trả về một trình tạo hành động thunk sẽ chạy lệnh gọi lại lời hứa và gửi các hành động vòng đời dựa trên lời hứa đã trả về.
  • configureStore: Như đã nêu trong tài liệu, [configureStore](https://redux-toolkit.js.org/api/configureStore)kết thúc [createStore](https://redux.js.org/api/createstore)để cung cấp các tùy chọn cấu hình đơn giản và mặc định tốt. Nó có thể tự động kết hợp các bộ giảm bớt lát cắt của chúng tôi, thêm bất kỳ phần mềm trung gian Redux nào mà chúng tôi cung cấp, bao gồm redux-thunktheo mặc định và cho phép sử dụng Phần mở rộng Redux DevTools. Phương thức này chấp nhận một đối tượng cấu hình đơn với nhiều thuộc tính; quan trọng nhất là reducer, một đối tượng lưu trữ các bộ giảm bớt lát cắt, như được thấy trong ứng dụng ví dụ ngược trong src/app/store.js.

Giới thiệu về Redux Persist

Redux Persist là một thư viện giúp bạn dễ dàng lưu kho Redux ở dạng lưu trữ liên tục (ví dụ: lưu trữ cục bộ) để ngay cả sau khi làm mới trình duyệt, trạng thái vẫn sẽ được giữ nguyên. Nó cũng bao gồm các tùy chọn cho phép chúng tôi tùy chỉnh trạng thái tồn tại và bù nước.

Để bắt đầu với Redux Persist, trước tiên chúng ta cần cài đặt nó, có thể thực hiện bằng một trong các lệnh sau:

npm i redux-persist
  
// OR
  
yarn add redux-persist

Để chứng minh cách hoạt động của Redux Persist, chúng tôi sẽ sử dụng bootstrap ứng dụng phản ví dụ trong phần cuối cùng bằng cách sử dụng npx create-react-app my-app --template reduxlệnh. Đây là cửa hàng của ứng dụng truy cập trông như thế nào:

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

Để duy trì cửa hàng ở trên với thiết lập và cấu hình cơ bản của Redux Persist, đây là giao diện của cửa hàng:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from '../features/counter/counterSlice';
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, counterReducer)

export const store = configureStore({
  reducer: {
    counter: persistedReducer
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    })
})

export const persistor = persistStore(store)

Hai chức năng cần lưu ý ở trên là persistReducerpersistStore.

  • persistReducerlà một bộ giảm thiểu nâng cao chấp nhận một đối tượng cấu hình và bộ giảm tốc được duy trì. Đối tượng cấu hình được sử dụng để chỉ định cách duy trì và bù nước cho bộ giảm tốc được cung cấp. Trong cấu hình ở trên bằng cách sử dụng thuộc tính lưu trữ, chúng tôi đã chỉ định rằng counterReducertrạng thái được duy trì cho bộ nhớ cục bộ. Ngoài lưu trữ cục bộ, chúng ta cũng có thể sử dụng các công cụ lưu trữ khác như [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage).
  • persistStorelà hàm thực hiện trạng thái tồn tại và bù nước và nó nhận trong cửa hàng Redux làm tham số. Với chức năng này, cửa hàng của chúng tôi sẽ được lưu vào bộ nhớ cục bộ và trạng thái sẽ vẫn còn ngay cả sau khi làm mới trình duyệt.

Trong thiết lập ở trên trong cofigureStoreviệc sử dụng middlewaretrường đã bỏ qua tất cả các loại hành động được gửi bởi Redux Persist. Điều này được thực hiện để chúng tôi sẽ không gặp lỗi khi đọc bảng điều khiển của trình duyệt a non-serializable value was detected in the state.

Đối với các trường hợp sử dụng mà chúng tôi có thể muốn trì hoãn việc hiển thị giao diện người dùng của mình cho đến khi dữ liệu liên tục có sẵn trong cửa hàng Redux. Redux Persist bao gồm [PersistGate](https://github.com/ryanwillis/reduxjs-toolkit-persist/blob/main/docs/PersistGate.md)thành phần. Để sử dụng PersistGate, hãy index.jsthêm các nhập sau:

import { persistor, store } from './app/store';
import { PersistGate } from 'redux-persist/integration/react';

Bây giờ, hãy sửa đổi renderphương thức để trông giống như sau:

root.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={<Loader />} persistor={persistor}>
        <App />
      </PersistGate>
    </Provider>
  </React.StrictMode>
);

Đây là tất cả những gì chúng ta cần để bắt đầu với Redux Persist. Để biết các tùy chỉnh và cấu hình cụ thể cho các trường hợp sử dụng khác, bạn có thể xem State Reconciler , Blacklist & WhitelistNested Persists , và Transforms .

Bây giờ chúng ta đã hiểu cách hoạt động của Redux Toolkit và Redux Persist. Hãy xem làm thế nào để kết hợp chúng để xây dựng một cái gì đó hữu ích.

Tạo giỏ hàng với Redux Toolkit và Redux Persist

Tôi đã tạo một repo dành cho người mới bắt đầu với một mẫu mà chúng tôi sẽ sử dụng để tạo giỏ hàng để chúng tôi có thể chỉ tập trung vào việc triển khai.

Bước tiếp theo là sao chép repo GitHub và cài đặt các phụ thuộc cần thiết. Chúng ta có thể thực hiện việc này bằng các lệnh sau:

git clone -b starter https://github.com/Tammibriggs/shopping-cart.git

cd shopping-cart

npm install @reduxjs/toolkit react-redux redux-persist

Trong mẫu bắt đầu, tôi đã bao gồm Trang chủ nơi các mặt hàng được hiển thị và Trang Giỏ hàng để xem các mặt hàng được thêm vào giỏ hàng. Sau khi khởi động ứng dụng nhân bản bằng npm startlệnh, chúng ta sẽ thấy Trang chủ trong trình duyệt của mình:

2

Để điều hướng trang Giỏ hàng, hãy nhấp vào biểu tượng giỏ hàng nằm ở dưới cùng bên phải của trang và chúng ta sẽ thấy màn hình sau:

3

Bây giờ chúng ta đã có một mẫu, hãy bắt đầu với việc triển khai. Đầu tiên, chúng ta sẽ sử dụng createSlicephương pháp tạo một lát cắt với các bộ giảm bớt để thực hiện những việc sau:

  • Thêm một mặt hàng vào giỏ hàng
  • Tăng số lượng một mặt hàng trong giỏ hàng
  • Giảm số lượng một mặt hàng trong giỏ hàng
  • Xóa một mặt hàng khỏi giỏ hàng

Đây là những hành động liên quan đến việc triển khai giỏ hàng. Để tạo lát cắt, trong srcthư mục của ứng dụng sao chép, trước tiên, hãy tạo một reduxthư mục. Đây là nơi chúng tôi muốn đưa các tập tin liên quan đến quản lý nhà nước. Bây giờ, trong thư mục này, hãy tạo một cartSlice.jstệp và thêm các dòng mã sau:

// src/redux/cartSlice.js
import { createSlice } from '@reduxjs/toolkit';

const cartSlice = createSlice({
  name: 'cart',
  initialState: {
    cart: [],
  },
  reducers: {
    addToCart: (state, action) => {
      const itemInCart = state.cart.find((item) => item.id === action.payload.id);
      if (itemInCart) {
        itemInCart.quantity++;
      } else {
        state.cart.push({ ...action.payload, quantity: 1 });
      }
    },
    incrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      item.quantity++;
    },
    decrementQuantity: (state, action) => {
      const item = state.cart.find((item) => item.id === action.payload);
      if (item.quantity === 1) {
        item.quantity = 1
      } else {
        item.quantity--;
      }
    },
    removeItem: (state, action) => {
      const removeItem = state.cart.filter((item) => item.id !== action.payload);
      state.cart = removeItem;
    },
  },
});

export const cartReducer = cartSlice.reducer;
export const {
  addToCart,
  incrementQuantity,
  decrementQuantity,
  removeItem,
} = cartSlice.actions;

Trong đoạn mã trên, chúng tôi đã tạo một phần giỏ hàng với các bộ giảm sau:

  • addToCart: Nhận đối tượng vật phẩm được thêm vào trạng thái dưới dạng tải trọng. Để thêm mục, trước tiên chúng tôi kiểm tra xem nó đã tồn tại hay chưa bằng findphương pháp này; nếu có, chúng tôi tăng số lượng của nó, nhưng nếu không, chúng tôi thêm nó vào trạng thái bằng cách sử dụng pushphương thức.
  • incrementQuantity: Nhận một ID mặt hàng dưới dạng trọng tải, được sử dụng để tìm mặt hàng ở trạng thái bằng findphương pháp này và sau đó tăng số lượng của nó lên 1.
  • decrementQuantity: Bộ giảm tốc này nhận một ID mặt hàng làm trọng tải. Sử dụng ID, chúng tôi tìm và giảm số lượng mặt hàng ở trạng thái chỉ khi số lượng của nó lớn hơn 1.
  • removeItem: Nhận ID mục dưới dạng trọng tải sau đó được sử dụng để xóa khỏi trạng thái bằng filterphương pháp này.

Bây giờ bằng cách sử dụng trình tạo hành động và trình giảm bớt được xuất trong đoạn mã trên, hãy định cấu hình cửa hàng redux và bắt đầu gửi các hành động cho chức năng giỏ hàng. Trong reduxthư mục, hãy tạo một store.jstệp và thêm dòng mã sau vào đó:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";

export const store = configureStore({
  reducer: cartReducer
})

Bây giờ, hãy bao bọc các thành phần của chúng ta với <Provider>from react-redux, cửa hàng Redux của chúng ta làm chỗ dựa để tất cả các thành phần trong ứng dụng của chúng ta có thể truy cập và sử dụng trạng thái toàn cục. Trong index.jstệp trước tiên, hãy thêm các lần nhập sau:

// src/index.js
import { Provider } from 'react-redux';
import { store } from './redux/store';

Bây giờ, hãy sửa đổi renderhàm để trông giống như sau:

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}>
        <App />
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

Bây giờ chúng ta đã hoàn tất việc thiết lập và chúng ta có thể bắt đầu tương tác với cửa hàng của mình bằng cách sử dụng các hook React-Redux. Để đọc dữ liệu từ cửa hàng, chúng tôi sẽ sử dụng useSelectorhook, và để gửi các hành động, chúng tôi sẽ sử dụng useDispatchhook.

Thêm các mặt hàng vào giỏ hàng

Chúng ta có thể thêm một mặt hàng vào giỏ hàng bằng cách gọi trình addToCarttạo hành động trong hàm điều phối từ useDispatch, chuyển đối tượng mặt hàng sẽ được thêm vào dưới dạng tham số.

Trong Trang chủ của ứng dụng của chúng tôi, khi Add to Cartnhấp vào nút của một mặt hàng, chúng ta muốn mặt hàng đó được thêm vào giỏ hàng. Để thực hiện việc này, hãy truy cập src/components/Item.jsvà trước tiên hãy thêm các lần nhập sau:

// src/components/Item.js
import { useDispatch } from 'react-redux';
import {addToCart} from '../redux/cartSlice';

Tiếp theo, thêm dòng mã sau vào Itemthành phần trước returncâu lệnh.

// src/components/Item.js
const dispatch = useDispatch()

Bây giờ, trong returncâu lệnh, hãy sửa đổi Add to Cartnút để trông giống như sau:

// src/components/Item.js
<button 
  onClick={() => 
    dispatch(addToCart({
      id, title, image, price
    }))
  }>Add to Cart
</button>

Với điều này, khi chúng ta nhấp vào Add to Cartnút trên bất kỳ mặt hàng nào trong ứng dụng của mình, mặt hàng đó sẽ được thêm vào giỏ hàng. Để thêm dấu hiệu về điều này trong giao diện người dùng, chúng ta nên tăng số lượng trong biểu tượng giỏ hàng ở dưới cùng bên phải của ứng dụng.

Đi tới src/pages/Home.jsvà trước tiên hãy thêm nhập sau:

// src/pages/Home.js
import { useSelector } from 'react-redux';

Tiếp theo, thêm các dòng mã sau vào sau useNavigatehook trong Homecomponent:

// src/pages/Home.js
const cart = useSelector((state) => state.cart)

const getTotalQuantity = () => {
  let total = 0
  cart.forEach(item => {
    total += item.quantity
  })
  return total
}

Trong đoạn mã trên, chúng tôi đã sử dụng useSelectorhook để lấy trạng thái giỏ hàng từ cửa hàng Redux của chúng tôi. Sau đó, chúng tôi tạo một getTotalQuantityhàm trả về tổng số lượng mặt hàng trong cửa hàng. Bây giờ, để sử dụng chức năng này, hãy sửa đổi divvới classNamecủa shopping-cartđể trông giống như sau:

// src/pages/Home.js
<div className='shopping-cart' onClick={() => navigate('/cart')}>
  <ShoppingCart id='cartIcon'/>
  <p>{getTotalQuantity() || 0}</p>
</div>

Với điều này, sẽ có một chỉ báo trong giao diện hiển thị số lượng mặt hàng đã được thêm vào giỏ hàng.

4

Hiển thị các mặt hàng được thêm vào cửa hàng trên trang Giỏ hàng

Ngay cả sau khi thêm các mặt hàng vào cửa hàng của chúng tôi, nó vẫn sẽ trống khi chúng tôi chuyển đến trang Giỏ hàng bằng cách nhấp vào biểu tượng giỏ hàng ở dưới cùng bên phải.

Để hiển thị các mặt hàng, chúng tôi sẽ sử dụng useSelectormóc để lấy trạng thái giỏ hàng từ cửa hàng của chúng tôi và sau đó lập bản đồ qua đó.

Đi tới src/pages/Cart.jsvà trước tiên hãy thêm nhập sau:

// src/pages/Cart.js
import { useSelector } from 'react-redux'

Tiếp theo, thêm dòng mã sau vào Cartthành phần trước returncâu lệnh:

// src/pages/Cart.js
const cart = useSelector((state) => state.cart)

Tiếp theo, sửa đổi divvới a classNameđể cart__lefttrông giống như sau:

// src/pages/Cart.js
<div className="cart__left">
  <div>
    <h3>Shopping Cart</h3>
    {cart?.map((item) => (
      <CartItem
        key={item.id}
        id={item.id}
        image={item.image}
        title={item.title}
        price={item.price} 
        quantity={item.quantity}
      />
    ))}
  </div>
</div>

Với điều này, các mục được thêm vào trong cửa hàng sẽ được hiển thị trên giao diện.

Thêm chức năng quản lý giỏ hàng

Hãy thêm các chức năng để tăng và giảm số lượng của một mặt hàng trong giỏ hàng và xóa nó khỏi giỏ hàng. Chúng tôi đã tạo các bộ giảm bớt để xử lý những điều này, vì vậy bây giờ chúng tôi cần gửi các hành động tương ứng.

Để thực hiện việc này, hãy truy cập src/components/CartItem.jsvà sửa đổi toàn bộ tệp để bây giờ trông giống như sau:

// src/components/CartItem.js
import './cartItem.css'
import { incrementQuantity, decrementQuantity, removeItem} from '../redux/cartSlice'
import { useDispatch } from 'react-redux'

function CartItem({id, image, title, price, quantity=0}) {
  const dispatch = useDispatch()

  return (
    <div className="cartItem">
      <img className="cartItem__image" src={image} alt='item'/>
      <div className="cartItem__info">
        <p className="cartItem__title">{title}</p>
        <p className="cartItem__price">
          <small>$</small>
          <strong>{price}</strong>
        </p>
        <div className='cartItem__incrDec'>
          <button onClick={() => dispatch(decrementQuantity(id))}>-</button>
          <p>{quantity}</p>
          <button onClick={() => dispatch(incrementQuantity(id))}>+</button>
        </div>
        <button
          className='cartItem__removeButton' 
          onClick={() => dispatch(removeItem(id))}>
            Remove
        </button>
      </div>
    </div>
  )
}

export default CartItem

Trong đoạn mã trên, chúng tôi đã nhập incrementQuantity, decrementQuantityngười removeItemtạo hành động và gọi chúng trong dispatchhàm, chuyển cho chúng ID của mục. Các chức năng điều phối được gọi trong onClicktrình xử lý sự kiện của các nút tương ứng với trình tạo hành động.

Với điều này, khi chúng tôi truy cập trang Giỏ hàng và nhấp vào bất kỳ nút nào để quản lý một mặt hàng, các hành động tương ứng của chúng sẽ được thực hiện và trạng thái sẽ được cập nhật.

Bây giờ, những gì còn lại là hiển thị tổng giá và số lượng mặt hàng trong giỏ hàng. Để thực hiện việc này, hãy truy cập src/components/Total.jsvà trước tiên hãy thêm nhập sau:

// src/components/Total.js
import {useSelector} from 'react-redux'

Tiếp theo, thêm các dòng mã sau vào Totalthành phần trước returncâu lệnh:

// src/components/Total.js
const cart = useSelector((state) => state.cart)

const getTotal = () => {
  let totalQuantity = 0
  let totalPrice = 0
  cart.forEach(item => {
    totalQuantity += item.quantity
    totalPrice += item.price * item.quantity
  })
  return {totalPrice, totalQuantity}
}

Trong đoạn mã trên, chúng tôi đã lấy trạng thái giỏ hàng từ cửa hàng Redux và sau đó tạo một getTotalhàm trả về tổng giá và số lượng của mặt hàng trong giỏ hàng. Bây giờ để sử dụng điều này, hãy sửa đổi divvới classNamecủa total__pđể trông giống như sau:

// src/components/Total.js
<p className="total__p">
  total ({getTotal().totalQuantity} items) 
  : <strong>${getTotal().totalPrice}</strong>
</p>

Sau khi thêm các mặt hàng vào giỏ hàng, chúng ta sẽ thấy tổng giá và số lượng trên trang Giỏ hàng.

5

Trạng thái giỏ hàng tồn tại với Redux Persist

Ngay bây giờ, sau khi thêm các mặt hàng trong trạng thái giỏ hàng, ngay cả việc làm mới trình duyệt cũng sẽ xóa cửa hàng Redux khiến dữ liệu của chúng tôi bị mất, đây không phải là cách triển khai tốt cho giỏ hàng. Vì vậy, để tồn tại trong cửa hàng trong bộ nhớ cục bộ và bù nước khi ứng dụng tải lại, chúng tôi sẽ sử dụng Redux Persist, mà chúng tôi đã đề cập ở trên.

Đi tới src/redux/store.jsvà sửa đổi tệp để trông giống như sau:

// src/redux/store.js
import { configureStore } from "@reduxjs/toolkit";
import { cartReducer } from "./cartSlice";
import storage from 'redux-persist/lib/storage';
import {
  persistStore,
  persistReducer,
  FLUSH,
  REHYDRATE,
  PAUSE,
  PERSIST,
  PURGE,
  REGISTER,
} from 'redux-persist'

const persistConfig = {
  key: 'root',
  storage,
}

const persistedReducer = persistReducer(persistConfig, cartReducer)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
      },
    }),
})

export const persistor = persistStore(store)

Với điều này, chúng tôi đã thêm sự bền bỉ cho cửa hàng Redux của mình và chúng tôi đã hoàn thành việc xây dựng giỏ hàng của mình.

Sự kết luận

Giỏ hàng là một phần thiết yếu của mọi ứng dụng thương mại điện tử. Việc xây dựng nó bằng các công cụ phù hợp như hướng dẫn này giúp việc triển khai nó dễ dàng và đơn giản hơn. Trong hướng dẫn này, chúng ta đã học cách tạo giỏ hàng bằng Redux Toolkit và Redux Persist. Với điều này, bạn sẽ có thể thêm nó vào ứng dụng của mình một cách dễ dàng.

#react #reactjs #redux #javascript

Cách Tạo Giỏ Hàng Trong React Với Bộ Công Cụ Redux