Фреймворк React использовался для создания приложения счетчика. Приложение счетчика содержит два набора счетчиков. Один был реализован с помощью хука useReducer
, а другой был реализован с использованием пользовательского хука, реализованного с помощью useReducer
. Этот пост проведет вас через шаги, чтобы воспроизвести одно и то же приложение счетчика. Давайте погрузимся.
Счетчик с useReducer
Хук useReducer
— это вариант useState,
, который позволяет отдельно обновлять логику. useReducer
используется для обработки сложных состояний или в случаях, когда одно состояние зависит от другого.
В то время как
useState
принимает в качестве аргумента только начальное состояние,useReducer
принимает в качестве аргументов начальное состояние и редьюсер. Редьюсер — это чистая функция, которая принимает текущее состояние и объект, называемый действием, и возвращает новое состояние. -Крис Минник
Вы начинаете с создания компонента с именем ReducerCounter
. Этот компонент содержит useReducer
для приложения счетчика.
import { useReducer } from "react"; const initialValue = { count: 0, value: 0, }; function reducer(state, action) { switch (action.type) { case "increment": return { ...state, count: Number(state.count) + 1 }; case "decrement": return { ...state, count: Number(state.count) - 1 }; case "setValue": if (action.payload) { return { ...state, count: action.payload }; } return initialValue; case "addValue": return { ...state, value: action.payload }; case "reset": return initialValue; default: return state; } }
В приведенном выше коде вы импортируете useReducer
и определяете начальное значение ваших состояний.
Далее вы определяете свой редьюсер, который слушает действия и по ним возвращает нужное состояние.
Функция редуктора имеет пять действий:
increment
:что увеличивает значение счетчика на 1.decrement:
, который уменьшает значение счетчика на 1.setValue
: счетчик начинается с любого введенного вами значения.addValue
:сохраняет введенное вами значение, чтобыsetValue
мог получить к нему доступ.reset:
, который устанавливает значение счетчика на 0.
export default function ReducerCounter() { const [state, dispatch] = useReducer(reducer, initialValue); function increment() { dispatch({ type: "increment" }); } function decrement() { dispatch({ type: "decrement" }); } function setValue() { dispatch({ type: "setValue", payload: state.value }); } function reset() { dispatch({ type: "reset" }); } return ( <div className="middle"> <h1> Counter app created with useReducer</h1> <h2>{state.count}</h2> <div className="icons"> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> <div className="search-bar"> <input type="number" id="set" value={state.value} onChange={(e) => { dispatch({ type: "addValue", payload: e.target.value }); }} placeholder="Enter a number" /> </div> <div className="icons"> <button onClick={setValue}>Set Value</button> <button onClick={reset}> Reset</button> </div> </div> ); }
Далее в вашем компоненте у вас есть функции, основанные на случаях, описанных выше.
Хук useReducer
принимает два аргумента. Во-первых, это функция редуктора, которая отвечает за управление и обновление нашего состояния. Второе — это начальное значение нашего состояния.
Хук useReducer возвращает два значения.
- Штат.
- Отправка: эта функция используется в ответ на события. Он принимает объект действия, который состоит из типа и необязательной полезной нагрузки.
Теперь оператор return содержит JavaScript XML (JSX) для пользовательского интерфейса (UI) вашего приложения-счетчика.
Если вы продолжите и нажмете кнопки для увеличения, уменьшения, установки значения и сброса, вы сможете увидеть, как значение увеличивается, уменьшается, устанавливается и сбрасывается.
Всякий раз, когда вы нажимаете на соответствующую кнопку, она отправляет действие типа увеличения, уменьшения, установки значения или сброса; следовательно, редьюсер обновляет состояние и возвращает обновленное состояние.
Счетчик с нестандартным крючком
Для этого вам нужно будет создать собственный хук, используя useReducer
.
Пользовательские хуки — это функции, которые используют встроенные хуки для инкапсуляции повторно используемых функций. -Крис Минник
Вам нужно создать компонент для своего пользовательского хука и написать нашу собственную реализацию useReducer
. Назовем компонент useCounter
. Как обычно, вы начинаете с определения ловушки useReducer
. Пользовательские хуки, как и встроенные хуки, имеют имена, начинающиеся с использования. Это скорее полезное соглашение, чем требование.
function useCounter() { const [state, dispatch] = useReducer(reducer, initialValue); function increment() { dispatch({ type: "increment" }); } function decrement() { dispatch({ type: "decrement" }); } function setValue() { dispatch({ type: "setValue", payload: state.value }); } function reset() { dispatch({ type: "reset" }); } return [state, dispatch, increment, decrement, setValue, reset]; } export default useCounter;
Пользовательский хук принимает те же аргументы, что и обычный хук useReducer, reducer и состояние. Пользовательский хук возвращает массив.
Чтобы использовать этот пользовательский хук, вы должны импортировать его в компонент и деконструировать массив. Для этого вам нужно создать еще один компонент с именем Body
, но вы можете дать ему любое имя по вашему выбору.
import React from 'react' import './Body.css' import useCounter from '../Pages/useCounter' const Body = () => { const [state, dispatch, increment, decrement, setValue, reset] = useCounter() return ( <div className='middle'> <h1> Counter app created with the useCounter custom hook</h1> <h2>{state.count}</h2> <div className= 'icons'> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> <div className='search-bar'> <input type='number' id='set' value={state.value} onChange={(e)=>{dispatch({type:'addValue', payload:e.target.value})}} placeholder='Enter a number'/> </div> <div className='icons'> <button onClick ={setValue}>Set Value</button> <button onClick={reset}> Reset</button> </div> </div> ) } export default Body
Вторая строка кода — это импорт для файла CSS, а стили находятся здесь. В третьей строке вы импортируете пользовательский счетчик. Ваш компонент деконструирует массив для доступа к переменным. Затем, наконец, компонент body возвращает разметку для счетчика, созданного с помощью пользовательского хука. JSX похож на хук useReducer
.
И если мы запустим это в браузере, вуаля! Он работает так же, как useReducer
.
Другие функции счетчика
Маршрутизация
Приложение счетчика представляет собой одностраничное приложение (SPA). При наличии SPA другим сайтам будет сложно ссылаться на данные на вашем сайте или поисковым системам будет сложно индексировать данные на вашем сайте. Решением этой проблемы является процесс сопоставления URL-адресов с тем, что происходит внутри приложения JavaScript. Этот процесс называется маршрутизация.
Для перехода от одного приложения-счетчика к другому мы использовали React Router.
React Routers не устанавливается вместе с приложением Create React по умолчанию, поэтому вам придется установить его, прежде чем вы начнете его использовать. Вы можете установить react-router-dom
с помощью npm, введя в терминал следующую команду:
npm установить реакцию-маршрутизатор-дом
После его установки вы можете импортировать компоненты, функции и хуки из библиотеки в любой из ваших компонентов, которые будут использовать маршрутизацию. Для вашего приложения счетчика вам понадобятся три части React Router:
- Компонент маршрутизатора
- Связующий компонент
- Компонент маршрута
Компонент маршрутизатора
Это компонент верхнего уровня, который делает возможной маршрутизацию. Ваш компонент маршрутизатора для приложения счетчика — BrowserRouter.
.
import { BrowserRouter } from "react-router-dom"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <BrowserRouter> <App /> </BrowserRouter> </React.StrictMode> );
Приведенный выше код должен быть в вашем файле index.js. Первая строка кода содержит импорт для нашего компонента маршрутизатора, который называется BrowserRouter,
, и вы используете его для переноса компонента App
, который является вашим приложением-счетчиком. Это позволит маршрутизировать внутри приложения счетчика.
Связывание с маршрутами
Для приложения счетчика вы будете использовать Link
и NavLink
для связи компонентов. Link
предназначен для ссылок, которые не нуждаются в выделении, а NavLink
используется, когда вы хотите выделить ссылку как активную.
import React, { useContext } from "react"; import { FaCuttlefish, FaEdgeLegacy, FaHome, FaInfo, FaInfoCircle, FaMoon, FaRegRegistered, FaSun, } from "react-icons/fa"; import { Link, NavLink } from "react-router-dom"; import "./NavBar.css"; import { ThemeContext } from "../App"; const NavBar = () => { const { toggleTheme, theme } = useContext(ThemeContext); function getActive({ isActive }) { return { border: isActive ? "2px solid coral" : "none" }; } return ( <nav className="top"> <div className="left"> <Link to="/"> <span className="logo"> <FaEdgeLegacy /> <FaRegRegistered /> <FaInfo /> <FaCuttlefish /> </span> </Link> </div> <div className="right"> <NavLink style={getActive} end to="/" title="Home"> {" "} <FaHome /> </NavLink> <NavLink style={getActive} to="counterTwo" title="counter with useReducer" > {" "} <FaInfoCircle />{" "} </NavLink> <button className="theme" title="Theme" onClick={toggleTheme}> {" "} {theme === "light" ? <FaMoon /> : <FaSun />} </button> </div> </nav> ); }; export default NavBar;
Первым шагом является создание компонента NavBar
. Этот компонент будет содержать наши связывающие компоненты.
Хук useContext
импортируется из React,
, а ThemeContext
из вашего App
component. Это поможет вам переключаться между светлой и темной темами.
Внутри компонента NavBar
ThemeContext
деконструируется, чтобы вы могли получить доступ к theme
и toggleTheme
. Функция toggleTheme
используется в кнопке для изменения состояния theme
на темный или светлый режим. Также при нажатии на кнопку значок солнца меняется на луну и наоборот. Дополнительные пояснения будут даны по мере продвижения.
Функция getActive используется для определения активного маршрута и дает ему сплошную границу с цветным кораллом.
Важно добавить атрибут end
к NavLink,
, который имеет значение '/' для атрибута to
. Это сделает вашу функцию getActive
эффективной.
Если вы заметили в приведенном выше коде, некоторые значки импортированы. Это так называемые иконки React. Чтобы получить к ним доступ, вы должны установить react-icons
в качестве зависимости. Запустите этот код в своем терминале, чтобы установить значки реакции: npm install react-icons — save
Создание маршрутов
Компонент Route
— это тот, который фактически создает маршруты. Route
принимает атрибут с именем path
, который сравнивается с местоположением. Если есть марш, Route
сделает его дочерним:
<Routes> <Route path="/" element={<Home />} /> <Route path="/countertwo" element={ <CounterTwo /> } /> <Route path="*" element={<ErrorPage />} /> </Routes>
И если совпадения нет, route
с path
'*' отображает компонент ErrorPage
. Это будет выглядеть так:
Затем вы создаете компонент Foot, который будет служить нижним колонтитулом для вашего приложения-счетчика.
import React from "react"; import { FaCopyright, FaHome, FaInfoCircle } from "react-icons/fa"; import { Link } from "react-router-dom"; import "./Foot.css"; const Foot = () => { return ( <div className="bottom"> <div className="left-bottom"> <Link to="/"> <span> <FaCopyright /> AltSchool </span> </Link> </div> <div className="right-bottom"> <Link to="/"> <FaHome /> </Link> <Link to="/counterTwo"> <FaInfoCircle /> </Link> </div> </div> ); }; export default Foot;
Граница ошибки
Граница ошибок — это компонент, который перехватывает ошибки в своих дочерних компонентах.
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true }; } componentDidCatch(error, errorInfo) { // You can also log the error to an error reporting service //logErrorToMyService(error, errorInfo); } render() { if (this.state.hasError) { // You can render any custom fallback UI return ( <div className="error"> <h1>Something went wrong.</h1> <p>Please check the console for more information.</p> </div> ); } return this.props.children; } }
Из приведенного выше кода, как только ошибка обнаружена, граница ошибки предоставляет резервный пользовательский интерфейс и регистрирует ошибку. Метод render()
содержит пользовательский интерфейс, который будет отображаться после обнаружения ошибки.
После написания ErrorBoundary
вам нужно выделить компонент для тестирования кода. Я использовал компонент CounterTwo
. Вы можете использовать любой компонент по вашему выбору.
<Route path="/countertwo" element={ <ErrorBoundary> <CounterTwo /> </ErrorBoundary> } />
Компонент CounterTwo
заключен в один из ваших Route
и если он ловит ошибку, он отображает:
SEO реализация
Поисковая оптимизация (SEO) — одна из основных целей, которую разработчик будет учитывать при создании веб-приложений. SPA обычно не оптимизированы для SEO, но есть решение этой проблемы.
Вы собираетесь использовать библиотеку, которая поможет использовать включение метаданных и повысить SEO. Эта библиотека называется React-Helmet.
Чтобы установить React-Helmet, вам нужно открыть каталог проекта в терминале и ввести следующий синтаксис:
npm i react-helmet-async
После завершения установки вы можете импортировать и использовать библиотеку компонентов Helmet.
import { HelmetProvider } from "react-helmet-async"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <React.StrictMode> <HelmetProvider> <BrowserRouter> <App /> </BrowserRouter> </HelmetProvider> </React.StrictMode> );
Вы импортируете HelmetProvider
и используете его для переноса корневого приложения, как в приведенном выше коде, для создания контекста и предотвращения утечек памяти. Обратите внимание, что эти добавления выполняются в том же файле index.js, который является корневым приложением.
После чего вы добавляете тег meta
в наш файл index.html.
<meta name="description" content="Web site created using create-react-app" data-rh="true" />
Значения атрибутов дадут каждому route
уникальный заголовок на веб-странице. Вы сделаете это в нашем компоненте home
.
import React from "react"; import { Helmet } from "react-helmet-async"; import Body from "./Body"; import Foot from "./Foot"; const Home = () => { return ( <> <Helmet> <title>Counter:useCounter hook</title> <meta name="description" content="The official counter app homepage" /> <link rel="canonical" href="/" /> </Helmet> <Body /> <Foot /> </> ); }; export default Home;
Вы импортируете компонент Helmet
, чтобы можно было реализовать метатеги. Вы используете компонент Helmet
для переноса тегов title
, meta
и link
. Это дает домашнему компоненту уникальный заголовок вместо стандартного «Веб-сайт, созданный с помощью приложения create-реагировать». Следовательно, это помогает повысить SEO.
Вы также импортируете компоненты Body
и Foot
. Это является частью содержимого компонента Home
.
Это название (выделено красным) для приложения-счетчика, созданного с помощью пользовательского хука после реализации SEO.
Теперь пользовательский интерфейс выше предназначен для приложения-счетчика с useReducer. Давайте создадим компонент для SEO приложения-счетчика, созданного с помощью пользовательского хука.
import React from "react"; import { Helmet } from "react-helmet-async"; import Foot from "../Components/Foot"; import ReducerCounter from "./ReducerCounter"; const CounterTwo = () => { //throw new Error() return ( <> <Helmet> <title>Counter: with useReducer</title> <meta name="description" content="The counter app created with useReducer hoook in React" /> <link rel="canonical" href="/countertwo" /> </Helmet> <ReducerCounter /> <Foot /> </> ); }; export default CounterTwo;
Кодовая база аналогична кодовой базе useReducer. Внутри компонента CounterTwo
мы закомментировали функцию ошибки. Помните, что это компонент, который вы использовали для тестирования нашего ErrorBoundary
.
Это название (выделено красным) для приложения-счетчика, созданного с помощью useReducer
после реализации SEO.
Тема
Приложение счетчика имеет как светлый, так и темный режим. Это было реализовано с помощью хуков createContext
и useState
. Также необходимо создать два идентификатора: темный и светлый.
import React, { createContext, useState } from "react"; import { Route, Routes } from "react-router-dom"; import "./App.css"; import Home from "./Components/Home"; import NavBar from "./Components/NavBar"; import CounterTwo from "./Pages/CounterTwo"; import ErrorPage from "./Pages/ErrorPage"; export const ThemeContext = createContext(null); function App() { const [theme, setTheme] = useState("light"); const toggleTheme = () => { setTheme((curr) => (curr === "light" ? "dark" : "light")); }; return ( <ThemeContext.Provider value={{ theme, toggleTheme }}> <main className="App" id={theme}> <div className="container"> <NavBar /> <Routes> <Route path="/" element={<Home />} /> <Route path="/countertwo" element={ <ErrorBoundary> <CounterTwo /> </ErrorBoundary> } /> <Route path="*" element={<ErrorPage />} /> </Routes> </div> </main> </ThemeContext.Provider> ); } export default App;
useState
hook используется для управления состоянием темы (светлым или темным). Функция toggleTheme
используется для переключения между светлой и темной темой. Компонент ThemeContext.Provider
component используется для обертывания всего приложения, чтобы текущая тема отражалась в приложении.
Коды, показанные выше, относятся к функции темы приложения счетчика. Чтобы увидеть полный код в App
component, пожалуйста, проверьте кодовую базу.
Световой режим выглядит так.
Объяснив другие интересные функции счетного приложения, вы можете проверить исходный код на GitHub. Возможно, вам будет интересно узнать, что идея создания этого приложения возникла из вопроса во втором семестре экзамена AltSchool Africa для разработчиков интерфейсов.
В заключение…
Это мой взгляд на использование useReducer
непосредственно и в пользовательском хуке для создания простого приложения-счетчика.Как бы вы это сделали? Ваш отзыв будет хорошо оценен. Я не могу дождаться, чтобы услышать от вас!