{"id":331601,"date":"2022-04-06T21:00:09","date_gmt":"2022-04-06T21:00:09","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=331601"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=331601","title":{"rendered":"<span>\u0422\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0432 React \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Redux-toolkit<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/656995\/\" rel=\"noopener noreferrer nofollow\">\u0422\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0432 React \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c css \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432 scss<\/a>. \u0415\u0441\u043b\u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u0442\u0451\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u0440\u043e\u0434\u043d\u043e\u0439 \u0440\u0435\u0430\u043a\u0442\u043e\u0432\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0451 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Redux<\/code>, \u0442\u043e\u0447\u043d\u0435\u0435 <code>redux-toolkit<\/code><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/walborn\/with-redux-theme\/tree\/habr\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 &#8212; \u0432\u0435\u0442\u043a\u0430 <strong>habr<\/strong><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/with-redux-theme-cevvne559-walborn.vercel.app\/\" rel=\"noopener noreferrer nofollow\">\u0414\u0435\u043c\u043e<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>Roadmap<\/h3>\n<p>\u041c\u044b \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e\u0447\u0442\u0438 \u0442\u0435 \u0436\u0435 \u0448\u0430\u0433\u0438, \u0447\u0442\u043e \u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437:<\/p>\n<ol>\n<li>\n<p><code>Run-up<\/code> \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>create-react-app<\/code> \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/p>\n<\/li>\n<li>\n<p><code>Redux<\/code> \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044f \u0442\u0435\u043c\u044b \u0441 <code>redux-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c<\/code><\/p>\n<\/li>\n<li>\n<p><code>CSS Variables<\/code> \u041e\u0431\u044a\u044f\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u0435\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0441\u0442\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><code>Bonus<\/code> \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u043e\u0443\u0442\u0438\u043d\u0433<\/p>\n<\/li>\n<\/ol>\n<h3>1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<ol>\n<li>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>create-react-app<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c <code>sass<\/code> \u0438 <code>classnames<\/code> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0438\u043b\u044f\u043c\u0438<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\">> npx create-react-app with-redux-theme --template redux > cd with-redux-theme > npm i sass classnames -S<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u0441\u0435 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/src<\/code>, \u0442\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043d\u0435\u0451<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\">> cd src<\/code><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0423\u0434\u0430\u043b\u0438\u043c \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\"># \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \/src > rm -rf app features App.css App.js App.test.js index.css logo.svg<\/code><\/pre>\n<p>4. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"bash\"># \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \/src > mkdir -p components\/Theme > touch index.scss root.js store.js > touch components\/Theme\/{index.js,index.module.scss,slice.js}<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 <code>\/src<\/code> \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u0430\u043a\u0438\u043c <\/p>\n<pre><code class=\"bash\"># \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 > tree src src \u251c\u2500\u2500 components \u2502\u00a0\u00a0 \u2514\u2500\u2500 Theme \u2502\u00a0\u00a0     \u251c\u2500\u2500 index.js \u2502\u00a0\u00a0     \u251c\u2500\u2500 index.module.scss \u2502\u00a0\u00a0     \u2514\u2500\u2500 slice.js \u251c\u2500\u2500 index.js \u251c\u2500\u2500 index.scss \u251c\u2500\u2500 root.js \u251c\u2500\u2500 store.js \u2514\u2500\u2500 ...<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0432\u043d\u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0442\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 <code>src\/index.js<\/code><\/p>\n<pre><code class=\"javascript\">\/\/ src\/index.js import React from 'react' import ReactDOM from 'react-dom\/client' import { Provider } from 'react-redux'  import Root from '.\/root' import store from '.\/store'  import '.\/index.scss'  const rootElement = document.getElementById('root') if (!rootElement) throw new Error('Failed to find the root element') const root = ReactDOM.createRoot(rootElement)  root.render(   &lt;React.StrictMode>     &lt;Provider store={store}>       &lt;Root \/>     &lt;\/Provider>   &lt;\/React.StrictMode> )<\/code><\/pre>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <code>App.js<\/code> \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0444\u0430\u0439\u043b <code>root.js<\/code> \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c <code>Root<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u043e\u0443\u0442\u044b \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043d\u043e \u0430 \u043f\u043e\u043a\u0430&#8230;<\/p>\n<pre><code class=\"javascript\">\/\/ src\/root.js const Root = () => ( &lt;div>There are will be routes&lt;\/div> )  export default Root<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u044b<\/p>\n<h3>2. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u0442\u0435\u043c\u044b<\/h3>\n<p>\u0421\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0441\u0442\u043e\u0440. \u0412 \u043d\u0435\u043c \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d \u043b\u0438\u0448\u044c \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u0442\u0435\u043c\u044b. \u0414\u0435\u043b\u0430\u0435\u043c \u0435\u0433\u043e \u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>counter<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0448\u0435\u043b \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0448 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0449\u0435.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/store.js import { configureStore } from '@reduxjs\/toolkit' import themeReducer from '.\/components\/theme\/slice'  export const store = configureStore({   reducer: {     theme: themeReducer,   }, })<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0430\u043c \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0435\u043c\u044b.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/components\/theme\/slice.js import { createSlice } from '@reduxjs\/toolkit'  \/\/ \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0443 \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \/\/ \u0435\u0441\u043b\u0438 \u0442\u0430\u043c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442, \u0442\u043e \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0443 \u0438\u0437 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u044b \/\/ \u0435\u0441\u043b\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0435\u0442, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0435\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 const getTheme = () => {   const theme = `${window?.localStorage?.getItem('theme')}`   if ([ 'light', 'dark' ].includes(theme)) return theme    const userMedia = window.matchMedia('(prefers-color-scheme: light)')   if (userMedia.matches) return 'light'    return 'dark' }  const initialState = getTheme()  export const themeSlice = createSlice({   name: 'theme',   initialState,   reducers: {     set: (state, action) => action.payload,   }, })  export const { set } = themeSlice.actions  export default themeSlice.reducer<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0443 \u043d\u0430\u0441 \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u043d\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u0438\u0437\u043c\u0435\u043d\u044f\u043b \u0442\u0435\u043c\u0443.<br \/>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"javascript\">\/\/ src\/components\/theme\/index.js import React from 'react' import { useSelector, useDispatch } from 'react-redux' import cn from 'classnames'  import { set } from '.\/slice' import styles from '.\/index.module.scss'  const Theme = ({ className }) => {   const theme = useSelector((state) => state.theme)   const dispatch = useDispatch()    React.useEffect(() => {     document.documentElement.dataset.theme = theme     localStorage.setItem('theme', theme)   }, [ theme ])    const handleChange = () => {     const next = theme === 'dak' ? 'light' : 'dark'     dispatch(set(next))   }    return (     &lt;div       className={cn(     className,     styles.root,     theme === 'dark' ? styles.dark : styles.light)}       onClick={handleChange}     \/>   ) }  export default Theme<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0438\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b src\/components\/theme\/index.module.scss<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"css\">\/\/ src\/components\/theme\/index.module.scss .root { position: relative;   border-radius: 50%;   display: block;   height: 24px;   overflow: hidden;   width: 24px;   transition: 0.5s all ease;   input {     display: none;   }   &amp;:hover {     cursor: pointer;   }   &amp;:before {     content: \"\";     display: block;     position: absolute;   }   &amp;.light:before {     animation-duration: 0.5s;     animation-name: sun;     background-color: var(--text-color);     border-radius: 50%;     box-shadow: 10px 0 0 -3.5px var(--text-color),       -10px 0 0 -3.5px var(--text-color),       0 -10px 0 -3.5px var(--text-color),       0 10px 0 -3.5px var(--text-color),       7px -7px 0 -3.5px var(--text-color),       7px 7px 0 -3.5px var(--text-color),       -7px 7px 0 -3.5px var(--text-color),       -7px -7px 0 -3.5px var(--text-color);     height: 10px;     left: 7px;     top: 7px;     width: 10px;     &amp;:hover {       background-color: var(--background-color);       box-shadow: 10px 0 0 -3.5px var(--background-color),                   -10px 0 0 -3.5px var(--background-color),                   0 -10px 0 -3.5px var(--background-color),                   0 10px 0 -3.5px var(--background-color),                   7px -7px 0 -3.5px var(--background-color),                   7px 7px 0 -3.5px var(--background-color),                   -7px 7px 0 -3.5px var(--background-color),                   -7px -7px 0 -3.5px var(--background-color);     }   }   &amp;.dark {     &amp;:before {       animation-duration: .5s;       animation-name: moon;       background-color: var(--text-color);       border-radius: 50%;       height: 20px;       left: 2px;       top: 2px;       width: 20px;       z-index: 1;       &amp;:hover {         background-color: var(--background-color);       }     }     &amp;:after {       animation-duration: .5s;       animation-name: moon-shadow;       background: var(--background-color);       border-radius: 50%;       content: \"\";       display: block;       height: 18px;       position: absolute;       right: -2px;       top: -2px;       width: 18px;       z-index: 2;     }   } }  @keyframes sun {   from {     background-color: var(--background-color);     box-shadow: 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color);   }   to {     background-color: var(--text-color);     box-shadow: 10px 0 0 -3.5px var(--text-color),                 -10px 0 0 -3.5px var(--text-color),                 0 -10px 0 -3.5px var(--text-color),                 0 10px 0 -3.5px var(--text-color),                 7px -7px 0 -3.5px var(--text-color),                 7px 7px 0 -3.5px var(--text-color),                 -7px 7px 0 -3.5px var(--text-color),                 -7px -7px 0 -3.5px var(--text-color);   } }  @keyframes moon {   from {     height: 0;     left: 12px;     top: 12px;     width: 0;   }   to {     height: 20px;     left: 2px;     top: 2px;     width: 20px;   } }  @keyframes moon-shadow {   from {     background-color: var(--background-color);     height: 0;     right: 7px;     top: 7px;     width: 0;   }   to {     background-color: var(--background-color);     height: 18px;     right: -2px;     top: -2px;     width: 18px;   } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>Theme<\/code> \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/root.js import Theme from '.\/components\/Theme'  const Root = () => (   &lt;>     &lt;h1>\u0422\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0432 React \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Redux-toolkit&lt;\/h1>   &lt;Theme \/>   &lt;\/> )  export default Root <\/code><\/pre>\n<p>\u0418 \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043a\u0430\u043a \u043d\u0430\u0434\u043e, \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u0435\u043c\u044b. \u0417\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u044b \u0438\u0445 \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0440\u0435\u0437 <code>css<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 <code>scss<\/code> \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0443\u0442. <code>scss<\/code>  \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0442\u0441\u044f \u0432 <code>css<\/code> \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0433\u043b\u0443\u043f\u043e, \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0441\u0442\u0430\u0445, \u0433\u0434\u0435 \u043e\u043d\u0438 \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u044e\u0442.<\/p>\n<pre><code class=\"css\">\/\/ src\/index.scss :root[data-theme=\"light\"] {   --background-color: #ffffff;   --text-color: #1C1E21; }  :root[data-theme=\"dark\"] {   --background-color: #18191a;   --text-color: #f5f6f7; }  body {   background: var(--background-color);   color: var(--text-color); }<\/code><\/pre>\n<p>\u0423\u0440\u0430! \u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442! \u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u0435\u0449\u0430\u043d\u043d\u044b\u0439 \u0431\u043e\u043d\u0443\u0441 &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u043e\u0432<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442\u0438\u043d\u0433<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443<\/p>\n<pre><code class=\"bash\">> npm i react-router-dom -S<\/code><\/pre>\n<p>\u041e\u0431\u0435\u0440\u043d\u0435\u043c \u0432\u0441\u0435 \u0432 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 <code>BrowserRouter<\/code> \u043e\u0442 <code>react-router<\/code><\/p>\n<pre><code class=\"javascript\">import React from 'react' import ReactDOM from 'react-dom\/client' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom'  import * as serviceWorker from '.\/serviceWorker' import Root from '.\/root' import store from '.\/store'  import '.\/index.scss'  const rootElement = document.getElementById('root') if (!rootElement) throw new Error('Failed to find the root element') const root = ReactDOM.createRoot(rootElement)  root.render(   &lt;React.StrictMode>     &lt;BrowserRouter>       &lt;Provider store={store}>         &lt;Root \/>       &lt;\/Provider>     &lt;\/BrowserRouter>   &lt;\/React.StrictMode> )  serviceWorker.unregister()<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 <code>src\/root.js<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434<\/p>\n<pre><code class=\"javascript\">import { Routes, Route } from 'react-router-dom'  import Layout from '.\/components\/Layout' import Home from '.\/pages\/Home' import NoMatch from '.\/pages\/NoMatch'  const Root () => (   &lt;Routes>     &lt;Route path=\"\/\" element={&lt;Layout \/>}>       &lt;Route index element={&lt;Home \/>} \/>       &lt;Route path=\"*\" element={&lt;NoMatch \/>} \/>     &lt;\/Route>   &lt;\/Routes> )  export default Root<\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b<\/p>\n<pre><code class=\"bash\">> mkdir -p src\/pages\/{Home,NoMatch} src\/components\/Layout > touch src\/pages\/Home\/index.js src\/pages\/NoMatch\/index.js > touch src\/components\/Layout\/index.js<\/code><\/pre>\n<p>\u0421\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044f \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u043b \u0432 \u043f\u0430\u043f\u043a\u0443 <code>\/pages<\/code>.  \u041f\u043e\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u0432 <code>NextJS<\/code> \u0438 \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0435\u0439 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u043e\u0439. <\/p>\n<pre><code class=\"javascript\">\/\/ src\/components\/Layout\/index.js import { Outlet } from 'react-router-dom'  import Theme from '..\/Theme'  const Layout = () => (   &lt;>     &lt;Theme \/>     &lt;main>       &lt;Outlet \/>     &lt;\/main>   &lt;\/> )  export default Layout<\/code><\/pre>\n<pre><code class=\"javascript\">\/\/ src\/pages\/Home\/index.js const Home = () => &lt;h1>Home&lt;\/h1>  export default Home<\/code><\/pre>\n<pre><code class=\"javascript\">\/\/ src\/pages\/NoMatch\/index.js import { Link } from 'react-router-dom'  const NoMatch = () => (   &lt;>     &lt;h1>Page Not Found&lt;\/h1>     &lt;h2>We could not find what you were looking for.&lt;\/h2>     &lt;p>       &lt;Link to=\"\/\">Go to the home page&lt;\/Link>     &lt;\/p>   &lt;\/> )  export default NoMatch<\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435  <code>Home<\/code>, \u0430 \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e <a href=\"https:\/\/with-redux-theme-cevvne559-walborn.vercel.app\/something\" rel=\"noopener noreferrer nofollow\">\u0434\u0440\u0443\u0433\u0443\u044e<\/a>, \u0442\u043e \u043d\u0430\u043c \u043e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430 <code>NoMatch<\/code><\/p>\n<h3>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h3>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>redux-toolkit<\/code> \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0451\u043c\u043d\u043e\u0439 \u0442\u0435\u043c\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0435\u0449\u0435 \u043f\u0440\u043e\u0449\u0435. \u041a \u0442\u043e\u043c\u0443 \u0436\u0435, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0441\u0451 \u0440\u0430\u0432\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u0442\u043e \u044d\u0442\u043e\u0442 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u0435\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430. \u0414\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043c\u044b\u0441\u043b\u044f\u043c\u0438 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u0434 \u0438\u043b\u0438 \u0437\u0430\u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u044b, \u0435\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0435 \u044f\u0441\u043d\u043e &#8212; \u0441 \u0443\u0434\u043e\u0432\u043e\u043b\u044c\u0441\u0442\u0432\u0438\u0435\u043c \u0432\u0441\u0435\u043c \u043e\u0442\u0432\u0435\u0447\u0443!<\/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\/post\/659491\/\"> https:\/\/habr.com\/ru\/post\/659491\/<\/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_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u042d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435\u043c \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/656995\/\" rel=\"noopener noreferrer nofollow\">\u0422\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0432 React \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c css \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432 scss<\/a>. \u0415\u0441\u043b\u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437 \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438 \u0442\u0451\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 \u0447\u0435\u0440\u0435\u0437 \u0440\u043e\u0434\u043d\u043e\u0439 \u0440\u0435\u0430\u043a\u0442\u043e\u0432\u0441\u043a\u0438\u0439 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442, \u0442\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0441\u0451 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Redux<\/code>, \u0442\u043e\u0447\u043d\u0435\u0435 <code>redux-toolkit<\/code><\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/github.com\/walborn\/with-redux-theme\/tree\/habr\" rel=\"noopener noreferrer nofollow\">\u0420\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 &#8212; \u0432\u0435\u0442\u043a\u0430 <strong>habr<\/strong><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/with-redux-theme-cevvne559-walborn.vercel.app\/\" rel=\"noopener noreferrer nofollow\">\u0414\u0435\u043c\u043e<\/a><\/p>\n<\/li>\n<\/ul>\n<h3>Roadmap<\/h3>\n<p>\u041c\u044b \u043f\u0440\u043e\u0434\u0435\u043b\u0430\u0435\u043c \u043f\u043e\u0447\u0442\u0438 \u0442\u0435 \u0436\u0435 \u0448\u0430\u0433\u0438, \u0447\u0442\u043e \u0438 \u0432 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0440\u0430\u0437:<\/p>\n<ol>\n<li>\n<p><code>Run-up<\/code> \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>create-react-app<\/code> \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443<\/p>\n<\/li>\n<li>\n<p><code>Redux<\/code> \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u0435\u043b\u044f \u0442\u0435\u043c\u044b \u0441 <code>redux-\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c<\/code><\/p>\n<\/li>\n<li>\n<p><code>CSS Variables<\/code> \u041e\u0431\u044a\u044f\u0432\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u0435\u043c\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u043b\u0438\u044f\u0442\u044c \u043d\u0430 \u0441\u0442\u0438\u043b\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432<\/p>\n<\/li>\n<li>\n<p><code>Bonus<\/code> \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u043e\u0443\u0442\u0438\u043d\u0433<\/p>\n<\/li>\n<\/ol>\n<h3>1. \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h3>\n<ol>\n<li>\n<p>\u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>create-react-app<\/code> \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c <code>sass<\/code> \u0438 <code>classnames<\/code> \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u0442\u0438\u043b\u044f\u043c\u0438<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\">> npx create-react-app with-redux-theme --template redux > cd with-redux-theme > npm i sass classnames -S<\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0432\u0441\u0435 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u044c, \u043d\u0430\u0445\u043e\u0434\u044f\u0441\u044c \u0432 \u043f\u0430\u043f\u043a\u0435 <code>\/src<\/code>, \u0442\u043e \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043d\u0435\u0451<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\">> cd src<\/code><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0423\u0434\u0430\u043b\u0438\u043c \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"bash\"># \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \/src > rm -rf app features App.css App.js App.test.js index.css logo.svg<\/code><\/pre>\n<p>4. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/p>\n<pre><code class=\"bash\"># \u043d\u0430\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 \/src > mkdir -p components\/Theme > touch index.scss root.js store.js > touch components\/Theme\/{index.js,index.module.scss,slice.js}<\/code><\/pre>\n<p>\u041f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0430\u043f\u043a\u0438 <code>\/src<\/code> \u0434\u043e\u043b\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c\u0441\u044f \u0442\u0430\u043a\u0438\u043c <\/p>\n<pre><code class=\"bash\"># \u043f\u0435\u0440\u0435\u0439\u0434\u0435\u043c \u0432 \u043a\u043e\u0440\u0435\u043d\u044c \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 > tree src src \u251c\u2500\u2500 components \u2502\u00a0\u00a0 \u2514\u2500\u2500 Theme \u2502\u00a0\u00a0     \u251c\u2500\u2500 index.js \u2502\u00a0\u00a0     \u251c\u2500\u2500 index.module.scss \u2502\u00a0\u00a0     \u2514\u2500\u2500 slice.js \u251c\u2500\u2500 index.js \u251c\u2500\u2500 index.scss \u251c\u2500\u2500 root.js \u251c\u2500\u2500 store.js \u2514\u2500\u2500 ...<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u043c \u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u0434.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0432\u043d\u0435\u0441\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, \u0442\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430\u0448 <code>src\/index.js<\/code><\/p>\n<pre><code class=\"javascript\">\/\/ src\/index.js import React from 'react' import ReactDOM from 'react-dom\/client' import { Provider } from 'react-redux'  import Root from '.\/root' import store from '.\/store'  import '.\/index.scss'  const rootElement = document.getElementById('root') if (!rootElement) throw new Error('Failed to find the root element') const root = ReactDOM.createRoot(rootElement)  root.render(   &lt;React.StrictMode>     &lt;Provider store={store}>       &lt;Root \/>     &lt;\/Provider>   &lt;\/React.StrictMode> )<\/code><\/pre>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e <code>App.js<\/code> \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u0444\u0430\u0439\u043b <code>root.js<\/code> \u0441 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u043c <code>Root<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432 \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u043e\u0443\u0442\u044b \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b, \u043d\u043e \u0430 \u043f\u043e\u043a\u0430&#8230;<\/p>\n<pre><code class=\"javascript\">\/\/ src\/root.js const Root = () => ( &lt;div>There are will be routes&lt;\/div> )  export default Root<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 &#8212; \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0441\u0430\u043c\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043c\u044b<\/p>\n<h3>2. \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u0442\u0435\u043c\u044b<\/h3>\n<p>\u0421\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448 \u0441\u0442\u043e\u0440. \u0412 \u043d\u0435\u043c \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0434\u0438\u043d \u043b\u0438\u0448\u044c \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u0442\u0435\u043c\u044b. \u0414\u0435\u043b\u0430\u0435\u043c \u0435\u0433\u043e \u043f\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0438 \u0441 <code>counter<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0448\u0435\u043b \u0438\u0437 \u043a\u043e\u0440\u043e\u0431\u043a\u0438, \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0448 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043f\u0440\u043e\u0449\u0435.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/store.js import { configureStore } from '@reduxjs\/toolkit' import themeReducer from '.\/components\/theme\/slice'  export const store = configureStore({   reducer: {     theme: themeReducer,   }, })<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0441\u0430\u043c \u0440\u0435\u0434\u044c\u044e\u0441\u0435\u0440 \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0439 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0442\u0435\u043c\u044b.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/components\/theme\/slice.js import { createSlice } from '@reduxjs\/toolkit'  \/\/ \u043f\u044b\u0442\u0430\u0435\u043c\u0441\u044f \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0443 \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \/\/ \u0435\u0441\u043b\u0438 \u0442\u0430\u043c \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435\u0442, \u0442\u043e \u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0435\u043c\u0443 \u0438\u0437 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0441\u0438\u0441\u0442\u0435\u043c\u044b \/\/ \u0435\u0441\u043b\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043d\u0435\u0442, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0435\u043c\u043d\u0443\u044e \u0442\u0435\u043c\u0443 const getTheme = () => {   const theme = `${window?.localStorage?.getItem('theme')}`   if ([ 'light', 'dark' ].includes(theme)) return theme    const userMedia = window.matchMedia('(prefers-color-scheme: light)')   if (userMedia.matches) return 'light'    return 'dark' }  const initialState = getTheme()  export const themeSlice = createSlice({   name: 'theme',   initialState,   reducers: {     set: (state, action) => action.payload,   }, })  export const { set } = themeSlice.actions  export default themeSlice.reducer<\/code><\/pre>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u0443 \u043d\u0430\u0441 \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043d\u043e \u043d\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u044b \u0438\u0437\u043c\u0435\u043d\u044f\u043b \u0442\u0435\u043c\u0443.<br \/>\u0420\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u0435\u0433\u043e:<\/p>\n<pre><code class=\"javascript\">\/\/ src\/components\/theme\/index.js import React from 'react' import { useSelector, useDispatch } from 'react-redux' import cn from 'classnames'  import { set } from '.\/slice' import styles from '.\/index.module.scss'  const Theme = ({ className }) => {   const theme = useSelector((state) => state.theme)   const dispatch = useDispatch()    React.useEffect(() => {     document.documentElement.dataset.theme = theme     localStorage.setItem('theme', theme)   }, [ theme ])    const handleChange = () => {     const next = theme === 'dak' ? 'light' : 'dark'     dispatch(set(next))   }    return (     &lt;div       className={cn(     className,     styles.root,     theme === 'dark' ? styles.dark : styles.light)}       onClick={handleChange}     \/>   ) }  export default Theme<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0418 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0441\u0442\u0438\u043b\u0438 \u0432 \u0444\u0430\u0439\u043b src\/components\/theme\/index.module.scss<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"css\">\/\/ src\/components\/theme\/index.module.scss .root { position: relative;   border-radius: 50%;   display: block;   height: 24px;   overflow: hidden;   width: 24px;   transition: 0.5s all ease;   input {     display: none;   }   &amp;:hover {     cursor: pointer;   }   &amp;:before {     content: \"\";     display: block;     position: absolute;   }   &amp;.light:before {     animation-duration: 0.5s;     animation-name: sun;     background-color: var(--text-color);     border-radius: 50%;     box-shadow: 10px 0 0 -3.5px var(--text-color),       -10px 0 0 -3.5px var(--text-color),       0 -10px 0 -3.5px var(--text-color),       0 10px 0 -3.5px var(--text-color),       7px -7px 0 -3.5px var(--text-color),       7px 7px 0 -3.5px var(--text-color),       -7px 7px 0 -3.5px var(--text-color),       -7px -7px 0 -3.5px var(--text-color);     height: 10px;     left: 7px;     top: 7px;     width: 10px;     &amp;:hover {       background-color: var(--background-color);       box-shadow: 10px 0 0 -3.5px var(--background-color),                   -10px 0 0 -3.5px var(--background-color),                   0 -10px 0 -3.5px var(--background-color),                   0 10px 0 -3.5px var(--background-color),                   7px -7px 0 -3.5px var(--background-color),                   7px 7px 0 -3.5px var(--background-color),                   -7px 7px 0 -3.5px var(--background-color),                   -7px -7px 0 -3.5px var(--background-color);     }   }   &amp;.dark {     &amp;:before {       animation-duration: .5s;       animation-name: moon;       background-color: var(--text-color);       border-radius: 50%;       height: 20px;       left: 2px;       top: 2px;       width: 20px;       z-index: 1;       &amp;:hover {         background-color: var(--background-color);       }     }     &amp;:after {       animation-duration: .5s;       animation-name: moon-shadow;       background: var(--background-color);       border-radius: 50%;       content: \"\";       display: block;       height: 18px;       position: absolute;       right: -2px;       top: -2px;       width: 18px;       z-index: 2;     }   } }  @keyframes sun {   from {     background-color: var(--background-color);     box-shadow: 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color),                 0 0 0 -5px var(--background-color);   }   to {     background-color: var(--text-color);     box-shadow: 10px 0 0 -3.5px var(--text-color),                 -10px 0 0 -3.5px var(--text-color),                 0 -10px 0 -3.5px var(--text-color),                 0 10px 0 -3.5px var(--text-color),                 7px -7px 0 -3.5px var(--text-color),                 7px 7px 0 -3.5px var(--text-color),                 -7px 7px 0 -3.5px var(--text-color),                 -7px -7px 0 -3.5px var(--text-color);   } }  @keyframes moon {   from {     height: 0;     left: 12px;     top: 12px;     width: 0;   }   to {     height: 20px;     left: 2px;     top: 2px;     width: 20px;   } }  @keyframes moon-shadow {   from {     background-color: var(--background-color);     height: 0;     right: 7px;     top: 7px;     width: 0;   }   to {     background-color: var(--background-color);     height: 18px;     right: -2px;     top: -2px;     width: 18px;   } }<\/code><\/pre>\n<\/div>\n<\/details>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <code>Theme<\/code> \u043d\u0430 \u0433\u043b\u0430\u0432\u043d\u0443\u044e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443.<\/p>\n<pre><code class=\"javascript\">\/\/ src\/root.js import Theme from '.\/components\/Theme'  const Root = () => (   &lt;>     &lt;h1>\u0422\u0451\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0432 React \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Redux-toolkit&lt;\/h1>   &lt;Theme \/>   &lt;\/> )  export default Root <\/code><\/pre>\n<p>\u0418 \u0447\u0442\u043e\u0431\u044b \u0432\u0441\u0435 \u0437\u0430\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043a\u0430\u043a \u043d\u0430\u0434\u043e, \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0442\u0435\u043c\u044b. \u0417\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043c\u044b \u0438\u0445 \u0431\u0443\u0434\u0435\u043c \u0447\u0435\u0440\u0435\u0437 <code>css<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 <code>scss<\/code> \u043d\u0430\u043c \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0443\u0442. <code>scss<\/code>  \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0442\u0441\u044f \u0432 <code>css<\/code> \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u0433\u043b\u0443\u043f\u043e, \u043e\u043d \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0432\u043e \u0432\u0441\u0435\u0445 \u043c\u0435\u0441\u0442\u0430\u0445, \u0433\u0434\u0435 \u043e\u043d\u0438 \u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0443\u044e\u0442.<\/p>\n<pre><code class=\"css\">\/\/ src\/index.scss :root[data-theme=\"light\"] {   --background-color: #ffffff;   --text-color: #1C1E21; }  :root[data-theme=\"dark\"] {   --background-color: #18191a;   --text-color: #f5f6f7; }  body {   background: var(--background-color);   color: var(--text-color); }<\/code><\/pre>\n<p>\u0423\u0440\u0430! \u0412\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442! \u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043e\u0431\u0435\u0449\u0430\u043d\u043d\u044b\u0439 \u0431\u043e\u043d\u0443\u0441 &#8212; \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u043e\u0432<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u043e\u0443\u0442\u0438\u043d\u0433<\/h3>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443<\/p>\n<pre><code class=\"bash\">> npm i react-router-dom -S<\/code><\/pre>\n<p>\u041e\u0431\u0435\u0440\u043d\u0435\u043c \u0432\u0441\u0435 \u0432 \u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440 <code>BrowserRouter<\/code> \u043e\u0442 <code>react-router<\/code><\/p>\n<pre><code class=\"javascript\">import React from 'react' import ReactDOM from 'react-dom\/client' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom'  import * as serviceWorker from '.\/serviceWorker' import Root from '.\/root' import store from '.\/store'  import '.\/index.scss'  const rootElement = document.getElementById('root') if (!rootElement) throw new Error('Failed to find the root element') const root = ReactDOM.createRoot(rootElement)  root.render(   &lt;React.StrictMode>     &lt;BrowserRouter>       &lt;Provider store={store}>         &lt;Root \/>       &lt;\/Provider>     &lt;\/BrowserRouter>   &lt;\/React.StrictMode> )  serviceWorker.unregister()<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u043d\u043e \u0432 \u0444\u0430\u0439\u043b\u0435 <code>src\/root.js<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434<\/p>\n<pre><code class=\"javascript\">import { Routes, Route } from 'react-router-dom'  import Layout from '.\/components\/Layout' import Home from '.\/pages\/Home' import NoMatch from '.\/pages\/NoMatch'  const Root () => (   &lt;Routes>     &lt;Route path=\"\/\" element={&lt;Layout \/>}>       &lt;Ro<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-331601","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/331601","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=331601"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/331601\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=331601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=331601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=331601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}