{"id":337362,"date":"2022-08-22T09:00:32","date_gmt":"2022-08-22T09:00:32","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=337362"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=337362","title":{"rendered":"<span>\u0417\u0430\u043c\u0435\u0442\u043a\u0430 \u043e Redux \u0438 Zustand<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/jc\/hw\/st\/jchwst6a3nwlxlscnmuw5tdhmry.png\" data-src=\"https:\/\/habrastorage.org\/webt\/jc\/hw\/st\/jchwst6a3nwlxlscnmuw5tdhmry.png\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u0434\u043d\u044f\u0445 \u043c\u043d\u0435 \u043d\u0430 \u0433\u043b\u0430\u0437\u0430 \u043f\u043e\u043f\u0430\u043b\u0430\u0441\u044c <a href=\"https:\/\/blog.openreplay.com\/building-a-shopping-cart-in-react-with-redux-toolkit-and-redux-persist\">\u0441\u0442\u0430\u0442\u044c\u044f<\/a>, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/redux-toolkit.js.org\/\">Redux Toolkit<\/a> \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 <a href=\"https:\/\/github.com\/rt2zz\/redux-persist\">Redux Persist<\/a> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/Window\/localStorage\">localStorage<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/pmndrs\/zustand\">Zustand<\/a>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0435\u0433\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 \u043f\u0435\u0440\u0435\u0434 <code>Redux<\/code> \u043a\u0430\u043a \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430, \u0442\u0430\u043a \u0438 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/redux-toolkit\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e Redux Toolkit<\/a><\/li>\n<li><a href=\"https:\/\/my-js.org\/docs\/cheatsheet\/zustand\">\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u043e Zustand<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/redux-vs-zustand\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"realizaciya-korziny-tovarov-s-pomoschyu-redux\">\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Redux<\/code><\/h2>\n<p>  <\/p>\n<p>\u0421 \u0432\u0430\u0448\u0435\u0433\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u0438\u044f, \u044f \u043d\u0435 \u0431\u0443\u0434\u0443 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u0443\u044e \u0432\u044b\u0448\u0435 \u0441\u0442\u0430\u0442\u044c\u044e, \u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0443\u0441\u044c \u043a\u043e\u0434\u043e\u043c, \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u043c\u0441\u044f \u043a <code>Redux<\/code>.<\/p>\n<p>  <\/p>\n<p>\u0418\u0442\u0430\u043a, \u0447\u0442\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Redux<\/code> \u0438 <code>localStorage<\/code>?<\/p>\n<p>  <\/p>\n<ul>\n<li>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c 3 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"bash\">npm i @reduxjs\/toolkit react-redux redux-persist<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0447\u0430\u0441\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f (state slice) \u043a\u043e\u0440\u0437\u0438\u043d\u044b:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ src\/redux\/cartSlice.js import { createSlice } from '@reduxjs\/toolkit'; const cartSlice = createSlice({   name: 'cart',   \/\/ \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435   initialState: {     cart: [],   },   reducers: {     \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443     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 });       }     },     \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u0430, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435     incrementQuantity: (state, action) => {       const item = state.cart.find((item) => item.id === action.payload);       item.quantity++;     },     \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u0430, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435     decrementQuantity: (state, action) => {       const item = state.cart.find((item) => item.id === action.payload);       if (item.quantity === 1) {         item.quantity = 1       } else {         item.quantity--;       }     },     \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0438\u0437 \u043a\u043e\u0440\u0437\u0438\u043d\u044b     removeItem: (state, action) => {       const removeItem = state.cart.filter((item) => item.id !== action.payload);       state.cart = removeItem;     },   }, }); \/\/ \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 export const cartReducer = cartSlice.reducer; \/\/ \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 (\u044d\u043a\u0448\u0435\u043d\u044b) export const {   addToCart,   incrementQuantity,   decrementQuantity,   removeItem, } = cartSlice.actions;<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ src\/redux\/store.js import { configureStore } from \"@reduxjs\/toolkit\"; import { cartReducer } from \".\/cartSlice\"; export const store = configureStore({   reducer: cartReducer });<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u041e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ src\/index.js import { Provider } from 'react-redux'; import { store } from '.\/redux\/store';  root.render(   &lt;React.StrictMode>     &lt;BrowserRouter>       &lt;Provider store={store}>         &lt;App \/>       &lt;\/Provider>     &lt;\/BrowserRouter>   &lt;\/React.StrictMode> );<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u0418\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0445\u0443\u043a\u0430 <code>useSelector<\/code>:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { useSelector } from 'react-redux';  \/\/ \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 const cart = useSelector((state) => state.cart);<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u041e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0440\u0435\u0434\u0443\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>dispatch<\/code>, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u043e\u0433\u043e \u0445\u0443\u043a\u043e\u043c <code>useDispatch<\/code>:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { useDispatch } from 'react-redux'; import { addToCart } from \"..\/redux\/cartSlice\";  \/\/ \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 const dispatch = useDispatch(); dispatch(   addToCart(item) );<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>localStorage<\/code> \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ 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);<\/code><\/pre>\n<p>  <\/p>\n<ul>\n<li>\u0410 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043e\u0431\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0435\u0449\u0435 \u0432 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440:<\/li>\n<\/ul>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { store, persistor } from '.\/redux'; import { PersistGate } from 'redux-persist\/integration\/react';  root.render(   &lt;React.StrictMode>     &lt;BrowserRouter>       &lt;Provider store={store}>         &lt;PersistGate loading={&lt;div>Loading...&lt;\/div>} persistor={persistor}>           &lt;App \/>         &lt;\/PersistGate>       &lt;\/Provider>     &lt;\/BrowserRouter>   &lt;\/React.StrictMode> );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0433\u043b\u0430\u0441\u0438\u0442\u0435\u0441\u044c, \u043a\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c \u043c\u043d\u043e\u0433\u043e\u0432\u0430\u0442\u043e. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c, \u0443 \u043d\u0430\u0441 \u043d\u0435\u0442 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 <code>Redux<\/code> \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u0441\u043e\u0431\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<p>  <\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6301d182d5cd01344c92f195\" data-style=\"\" id=\"6301d182d5cd01344c92f195\" width=\"\"><\/div>\n<\/div>\n<p>  <\/p>\n<h2 id=\"realizacii-korziny-tovarov-s-pomoschyu-zustand\">\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Zustand<\/code><\/h2>\n<p>  <\/p>\n<p>\u041a\u043b\u043e\u043d\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">git clone -b starter https:\/\/github.com\/Tammibriggs\/shopping-cart.git<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c <code>Zustand<\/code>:<\/p>\n<p>  <\/p>\n<pre><code class=\"bash\">cd shopping-cart  npm i zustand<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 <code>src<\/code> \u0444\u0430\u0439\u043b <code>store\/cart.js<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import create from \"zustand\";  const useCartStore = create((set, get) => ({   \/\/ \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435   cart: [],   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443   addToCart: (item) => {     const { cart } = get();     const itemInCart = cart.find((i) => i.id === item.id);     const newCart = itemInCart       ? cart.map((i) =>           i.id === item.id ? { ...i, quantity: i.quantity + 1 } : i         )       : [...cart, { ...item, quantity: 1 }];     set({ cart: newCart });   },   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0438\u0437 \u043a\u043e\u0440\u0437\u0438\u043d\u044b   removeItem: (id) => {     const newCart = get().cart.filter((i) => i.id !== id);     set({ cart: newCart });   },   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u0430, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435   incrementQuantity: (id) => {     const newCart = get().cart.map((i) =>       i.id === id ? { ...i, quantity: i.quantity + 1 } : i     );     set({ cart: newCart });   },   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u0430, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435   decrementQuantity: (id) => {     const newCart = get().cart.map((i) =>       i.id === id ? { ...i, quantity: i.quantity - 1 } : i     );     set({ cart: newCart });   },   \/\/ \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435   getTotalItems: () => get().cart.length,   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435   getTotalQuantity: () => get().cart.reduce((x, y) => x + y.quantity, 0),   \/\/ \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0439 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435   getTotalPrice: () => get().cart.reduce((x, y) => x + y.price * y.quantity, 0), }));<\/code><\/pre>\n<p>  <\/p>\n<p><em>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u044d\u0442\u043e \u0432\u0441\u0435, \u0447\u0442\u043e \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Zustand<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0445\u0443\u043a\u0430 <code>useCartStore<\/code> \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<p><strong>\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430<\/strong><\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ pages\/Home.js import useCartStore from \"..\/store\/cart\";  function Home() {   \/\/ \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f   const { getTotalItems } = useCartStore(({ getTotalItems }) => ({     getTotalItems,   }));   \/\/ ... }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043d\u0430\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0440\u044f\u0434\u043e\u043c \u0441 \u0438\u043a\u043e\u043d\u043a\u043e\u0439 (\u043a\u043d\u043e\u043f\u043a\u043e\u0439) \u043a\u043e\u0440\u0437\u0438\u043d\u044b:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;div className=\"shopping-cart\" onClick={() => navigate(\"\/cart\")}>   &lt;ShoppingCart id=\"cartIcon\" \/>   &lt;p>{getTotalItems() || 0}&lt;\/p> &lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u0430 \u043a\u043e\u0440\u0437\u0438\u043d\u044b<\/strong><\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u0432\u0430\u0440\u044b, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ pages\/Cart.js const cart = useCartStore(({ cart }) => cart);<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u043e\u0432\u0430\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u0430\u0440\u0442\u043e\u0447\u0435\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;div>   &lt;h3>Shopping Cart&lt;\/h3>   {cart.map((i) => (     &lt;CartItem key={i.id} {...i} \/>   ))} &lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0430 \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435<\/strong><\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0435 \u0442\u043e\u0432\u0430\u0440\u0430 \u0434\u043b\u044f \u0433\u043b\u0430\u0432\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0443:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ components\/Item.js const addToCart = useCartStore(({ addToCart }) => addToCart);<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u043c\u0435\u043c\u043e\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">const addItem = useCallback(() => {   addToCart({ id, title, image, price }); }, []);<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u043d \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043a\u043d\u043e\u043f\u043a\u0438:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;button onClick={addItem}>Add to Cart&lt;\/button><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u041a\u0430\u0440\u0442\u043e\u0447\u043a\u0430 \u0442\u043e\u0432\u0430\u0440\u0430 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043a\u043e\u0440\u0437\u0438\u043d\u044b<\/strong><\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u0430\u0440\u0442\u043e\u0447\u043a\u0435 \u0442\u043e\u0432\u0430\u0440\u0430 \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u0430 \u0438\u0437 \u043a\u043e\u0440\u0437\u0438\u043d\u044b, \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f \u0438 \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ components\/CartItem.js const { incrementQuantity, decrementQuantity, removeItem } = useCartStore(   ({ incrementQuantity, decrementQuantity, removeItem }) => ({     incrementQuantity,     decrementQuantity,     removeItem,   }) );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043a\u043d\u043e\u043f\u043e\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;div className=\"cartItem\">   &lt;img className=\"cartItem__image\" src={image} alt=\"item\" \/>    &lt;div className=\"cartItem__info\">     &lt;p className=\"cartItem__title\">{title}&lt;\/p>     &lt;p className=\"cartItem__price\">       &lt;small>$&lt;\/small>       &lt;strong>{price}&lt;\/strong>     &lt;\/p>     &lt;div className=\"cartItem__incrDec\">       &lt;button         onClick={() => {           if (quantity === 1) return;           decrementQuantity(id);         }}       >         -       &lt;\/button>       &lt;p>{quantity}&lt;\/p>       &lt;button onClick={() => incrementQuantity(id)}>+&lt;\/button>     &lt;\/div>     &lt;button       className=\"cartItem__removeButton\"       onClick={() => removeItem(id)}     >       Remove     &lt;\/button>   &lt;\/div> &lt;\/div><\/code><\/pre>\n<p>  <\/p>\n<p><strong>\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430<\/strong><\/p>\n<p>  <\/p>\n<p>\u0412 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0438\u0437 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u044e\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0438 \u0441\u0442\u043e\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u043e\u0432\u0430\u0440\u043e\u0432, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0445\u0441\u044f \u0432 \u043a\u043e\u0440\u0437\u0438\u043d\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ components\/Total.js const { getTotalQuantity, getTotalPrice } = useCartStore(   ({ getTotalQuantity, getTotalPrice }) => ({     getTotalQuantity,     getTotalPrice,   }) );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">&lt;p className=\"total__p\">   total ({getTotalQuantity()} items) :{\" \"}   &lt;strong>${getTotalPrice()}&lt;\/strong> &lt;\/p><\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Zustand<\/code> \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u0440\u043e\u0449\u0435, \u0447\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Redux<\/code>. \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432 <strong>3 \u0440\u0430\u0437\u0430 \u043c\u0435\u043d\u044c\u0448\u0435 \u043a\u043e\u0434\u0430<\/strong>.<\/p>\n<p>  <\/p>\n<p><strong>\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>localStorage<\/code><\/strong><\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>localStorage<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Zustand<\/code> \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0430, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u0443\u044e \u0432 <code>create()<\/code>, \u0432 \u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a <code>persist<\/code>, \u0443\u043a\u0430\u0437\u0430\u0432 \u043a\u043b\u044e\u0447 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">import { persist } from \"zustand\/middleware\";  const useCartStore = create(   persist(     (set, get) => ({       \/\/ ...     }),     {       name: \"cart-storage\",       getStorage: () => localStorage,     }   ) );<\/code><\/pre>\n<p>  <\/p>\n<p>\u0413\u043e\u0442\u043e\u0432\u043e.<\/p>\n<p>  <\/p>\n<div class=\"oembed\">\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/6301d182b8903d345d8f61b4\" data-style=\"\" id=\"6301d182b8903d345d8f61b4\" width=\"\"><\/div>\n<\/div>\n<p>  <\/p>\n<h2 id=\"sravnenie-proizvoditelnosti\">\u0421\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438<\/h2>\n<p>  <\/p>\n<p><a href=\"https:\/\/github.com\/immerjs\/immer\">Immer<\/a>, \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0432 <code>Redux Toolkit<\/code>, \u0434\u0435\u043b\u0430\u0435\u0442 \u0435\u0433\u043e \u0447\u0443\u0434\u043e\u0432\u0438\u0449\u043d\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u043c. \u041f\u0440\u043e\u0432\u0435\u0434\u0435\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442.<\/p>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u0447\u0438\u0441\u0442\u043e\u0442\u044b \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0430 \u0443\u0434\u0430\u043b\u0438\u043c \u0432\u0435\u0441\u044c \u043a\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <code>localStorage<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f 2500 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ redux \/\/ src\/App.js \/\/ ... import { addToCart } from \".\/redux\/cartSlice\";  function App() {   const dispatch = useDispatch();    const addToCart2500Items = () => {     const times = [];     let id = 0;     for (let i = 0; i &lt; 25; i++) {       const start = performance.now();       for (let j = 0; j &lt; 100; j++) {         const item = {           id: id++,           title: \"title\",           image: \"image\",           price: \"price\",         };         \/\/ !         dispatch(addToCart(item));       }       const difference = performance.now() - start;       times.push(difference);     }     const time = Math.round(times.reduce((a, c) => (a += c), 0) \/ 25);     console.log(\"Time:\", time);   };    \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u043d\u043e\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b   useEffect(() => {     window.addEventListener(\"load\", addToCart2500Items);      return () => {       window.removeEventListener(\"load\", addToCart2500Items);     };   }, []);    \/\/ ... }<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"javascript\">\/\/ zustand \/\/ ... import useCartStore from \".\/store\/cart\";  function App() {   const addToCart = useCartStore(({ addToCart }) => addToCart);    const addToCart2500Items = () => {     const times = [];     let id = 0;     for (let i = 0; i &lt; 25; i++) {       const start = performance.now();       for (let j = 0; j &lt; 100; j++) {         const item = {           id: id++,           title: \"title\",           image: \"image\",           price: \"price\",         };         \/\/ !         addToCart(item);       }       const difference = performance.now() - start;       times.push(difference);     }     const time = Math.round(times.reduce((a, c) => (a += c), 0) \/ 25);     console.log(\"Time:\", time);   };    useEffect(() => {     window.addEventListener(\"load\", addToCart2500Items);      return () => {       window.removeEventListener(\"load\", addToCart2500Items);     };   }, []);    \/\/ ... }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u0440\u0435\u0434\u043d\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (\u043d\u0430 \u0432\u0430\u0448\u0435\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u044d\u0442\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0431\u0443\u0434\u0443\u0442 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0442\u044c\u0441\u044f):<\/p>\n<p>  <\/p>\n<ul>\n<li><code>Zustand<\/code> \u2014 <strong>10 \u043c\u0441<\/strong>;<\/li>\n<li><code>Redux<\/code> \u2014 <strong>250 \u043c\u0441<\/strong>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p><em>\u0412\u043d\u0438\u043c\u0430\u043d\u0438\u0435<\/em>: \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 2500 \u0442\u043e\u0432\u0430\u0440\u043e\u0432 <code>Redux<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f (sic!) \u0432 25 \u0440\u0430\u0437 \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0435\u043c <code>Zustand<\/code>.<\/p>\n<p>  <\/p>\n<p>\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u0434\u0430\u044e\u0442 \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b. \u041f\u043e\u043b\u0430\u0433\u0430\u044e, \u0446\u0438\u0444\u0440\u044b \u0433\u043e\u0432\u043e\u0440\u044f\u0442 \u0441\u0430\u043c\u0438 \u0437\u0430 \u0441\u0435\u0431\u044f.<\/p>\n<p>  <\/p>\n<p>\u0427\u0442\u043e \u043d\u0430\u0441\u0447\u0435\u0442 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u043e\u0432? \u2014 \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u0432\u044b. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/e6\/dk\/nz\/e6dknzcvqd4vk5xt4yc5rnhm_0u.png\" data-src=\"https:\/\/habrastorage.org\/webt\/e6\/dk\/nz\/e6dknzcvqd4vk5xt4yc5rnhm_0u.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/wz\/nq\/5l\/wznq5lwdcn5-b3xt4p1gd1lvh5q.png\" data-src=\"https:\/\/habrastorage.org\/webt\/wz\/nq\/5l\/wznq5lwdcn5-b3xt4p1gd1lvh5q.png\"\/>  <\/p>\n<p>  <\/p>\n<p>  <\/p>\n<p>\u042d\u0442\u043e \u0432\u0441\u0435, \u0447\u0435\u043c \u044f \u0445\u043e\u0442\u0435\u043b \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0441 \u0432\u0430\u043c\u0438 \u0432 \u0434\u0430\u043d\u043d\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435. \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u044b \u043d\u0430\u0448\u043b\u0438 \u0434\u043b\u044f \u0441\u0435\u0431\u044f \u0447\u0442\u043e-\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0438 \u043d\u0435 \u0437\u0440\u044f \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u044f. \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044e \u0437\u0430 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0438 happy coding!<\/p>\n<p>  <\/p>\n<hr\/>\n<p>  <\/p>\n<p><a href=\"https:\/\/cloud.timeweb.com\/vds-promo-8-rub?utm_source=habr&amp;utm_medium=blog_1560_476&amp;utm_campaign=habr&amp;utm_content=1560_476\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/co\/e2\/kh\/coe2kha8u8_pypip-2k3wk3ppa0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/co\/e2\/kh\/coe2kha8u8_pypip-2k3wk3ppa0.png\"\/><\/a><\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/company\/timeweb\/blog\/683726\/\"> https:\/\/habr.com\/ru\/company\/timeweb\/blog\/683726\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/jc\/hw\/st\/jchwst6a3nwlxlscnmuw5tdhmry.png\" data-src=\"https:\/\/habrastorage.org\/webt\/jc\/hw\/st\/jchwst6a3nwlxlscnmuw5tdhmry.png\"\/>  <\/p>\n<p>  \u041f\u0440\u0438\u0432\u0435\u0442, \u0434\u0440\u0443\u0437\u044c\u044f!<\/p>\n<p>  <\/p>\n<p>\u041d\u0430 \u0434\u043d\u044f\u0445 \u043c\u043d\u0435 \u043d\u0430 \u0433\u043b\u0430\u0437\u0430 \u043f\u043e\u043f\u0430\u043b\u0430\u0441\u044c <a href=\"https:\/\/blog.openreplay.com\/building-a-shopping-cart-in-react-with-redux-toolkit-and-redux-persist\">\u0441\u0442\u0430\u0442\u044c\u044f<\/a>, \u043f\u043e\u0441\u0432\u044f\u0449\u0435\u043d\u043d\u0430\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u043a\u043e\u0440\u0437\u0438\u043d\u044b \u0442\u043e\u0432\u0430\u0440\u043e\u0432 \u043d\u0430 <a href=\"https:\/\/ru.reactjs.org\/\">React<\/a> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/redux-toolkit.js.org\/\">Redux Toolkit<\/a> \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 <a href=\"https:\/\/github.com\/rt2zz\/redux-persist\">Redux Persist<\/a> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0432 <a href=\"https:\/\/developer.mozilla.org\/ru\/docs\/Web\/API\/Window\/localStorage\">localStorage<\/a>.<\/p>\n<p>  <\/p>\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0437\u0430\u043c\u0435\u0442\u043a\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <a href=\"https:\/\/github.com\/pmndrs\/zustand\">Zustand<\/a>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0435\u0433\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0430\u0445 \u043f\u0435\u0440\u0435\u0434 <code>Redux<\/code> \u043a\u0430\u043a \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043a\u043e\u0434\u0430, \u0442\u0430\u043a \u0438 \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/my-js.org\/docs\/guide\/redux-toolkit\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e Redux Toolkit<\/a><\/li>\n<li><a href=\"https:\/\/my-js.org\/docs\/cheatsheet\/zustand\">\u0428\u043f\u0430\u0440\u0433\u0430\u043b\u043a\u0430 \u043f\u043e Zustand<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/harryheman\/Blog-Posts\/tree\/master\/redux-vs-zustand\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a><\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u043c \u044d\u0442\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043f\u0440\u043e\u0448\u0443 \u043f\u043e\u0434 \u043a\u0430\u0442.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-337362","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/337362","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=337362"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/337362\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=337362"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=337362"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=337362"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}