Создание сайтов в Докучаевске, ДНР. Учебное пособие по React: создание приложения-калькулятора с нуля

 
 

В этом уроке мы создадим приложение React Calculator. Вы узнаете, как создавать каркасы, разрабатывать макеты, создавать компоненты, обновлять состояния и форматировать выходные данные.

Чтобы вдохновить вас, вот ссылка на развернутый проект, который мы будем создавать.

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

Планирование

Поскольку мы будем создавать приложение «Калькулятор», давайте выберем область, которая не слишком сложна для изучения, но и не слишком проста для охвата различных аспектов создания приложения.

Функции, которые мы реализуем, включают:

складывать, вычитать, умножать, делить

поддержка десятичных значений

рассчитать проценты

инвертировать значения

сбросить функциональность

форматировать большие числа

выходное изменение размера в зависимости от длины

Для начала мы нарисуем базовый каркас для отображения наших идей. Для этого можно использовать бесплатные инструменты вроде Figma или Diagrams.net.

Каркас

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

Цвета дизайна

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

Ниже приведены некоторые рекомендации, чтобы приложение выглядело великолепно:

обертка должна контрастировать с фоном

экран и значения кнопок должны быть легко читаемы

кнопка равенства должна быть другого цвета, чтобы придать некоторый акцент

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

Цветовая схема

Настройка проекта

Для начала откройте терминал в папке ваших проектов и создайте стандартный шаблон с помощью create-react-app. Для этого выполните команду:

npx create-react-app calculator

Это самый быстрый и простой способ настроить полностью работающее приложение React с нулевой конфигурацией. Все, что вам нужно сделать после этого, это запустить, cd calculatorчтобы переключиться на только что созданную папку проекта и npm startзапустить ваше приложение в браузере.

Просмотр в браузере

Как видите, он поставляется с некоторым шаблоном по умолчанию, поэтому далее мы немного очистим дерево папок проекта.

Найдите srcпапку, в которой будет жить логика вашего приложения, и удалите все, кроме App.jsсоздания вашего приложения, index.cssстиля вашего приложения и index.jsрендеринга вашего приложения в DOM.

Дерево проекта

Создать компоненты

Поскольку мы уже сделали каркас, мы уже знаем основные строительные блоки приложения. Это Wrapper, Screen, ButtonBoxи Button.

Сначала создайте componentsпапку внутри srcпапки. Затем мы создадим отдельный.jsфайл и.cssфайл для каждого компонента.

Если вы не хотите создавать эти папки и файлы вручную, вы можете использовать следующую однострочную строку для быстрой настройки:

cd src && mkdir components && cd components && touch Wrapper.js Wrapper.css Screen.js Screen.css ButtonBox.js ButtonBox.css Button.js Button.css

Обертка

Компонент Wrapperбудет фреймом, удерживающим все дочерние компоненты на месте. Это также позволит нам впоследствии центрировать все приложение.

Wrapper.js

import «. /Wrapper.css»;

const Wrapper = ({ children }) => {

return

{children}

;

 

};

export default Wrapper;

Wrapper.css

.wrapper {

width: 340px;

height: 540px;

padding: 10px;

border-radius: 10px;

background-color: #485461;

background-image: linear-gradient (315deg, #485461 0%, #28313b 74%) ;

}

Экран

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

В список функций мы включили изменение размера отображаемого вывода в зависимости от длины, что означает, что более длинные значения должны уменьшаться в размере. Для этого мы будем использовать небольшую (3,4 КБ gzip) библиотеку под названием react-textfit.

Чтобы установить его, запустите, npm i react-textfitа затем импортируйте и используйте его, как показано ниже.

Экран.js

import { Textfit } from «react-textfit»;

import «. /Screen.css»;

const Screen = ({ value }) => {

return (

{value}

 

) ;

};

export default Screen;

Экран.css

.screen {

height: 100px;

width: 100%;

margin-bottom: 10px;

padding: 0 10px;

background-color: #4357692d;

border-radius: 10px;

display: flex;

align-items: center;

justify-content: flex-end;

color: white;

font-weight: bold;

box-sizing: border-box;

}

КнопкаБокс

Компонент ButtonBox, как и Wrapperкомпонент, будет фреймом для дочерних элементов — только на этот раз для Buttonкомпонентов.

ButtonBox.js

import «. /ButtonBox.css»;

const ButtonBox = ({ children }) => {

return

{children}

;

 

};

export default ButtonBox;

ButtonBox.css

.buttonBox {

width: 100%;

height: calc (100% — 110px) ;

display: grid;

grid-template-columns: repeat (4, 1fr) ;

grid-template-rows: repeat (5, 1fr) ;

grid-gap: 10px;

}

Кнопка

Компонент Buttonобеспечит интерактивность для приложения. Каждый компонент будет иметь свойства valueи onClick.

В таблицу стилей мы также включим стили для equalкнопки. Позже мы будем использовать Buttonсвойства для доступа к классу.

Кнопка.js

import «. /Button.css»;

const Button = ({ className, value, onClick }) => {

return (

 

 

) ;

};

export default Button;

Кнопка.css

button {

border: none;

background-color: rgb (80, 60, 209) ;

font-size: 24px;

color: rgb (255, 255, 255) ;

font-weight: bold;

cursor: pointer;

border-radius: 10px;

outline: none;

}

button: hover {

background-color: rgb (61, 43, 184) ;

}

.equals {

grid-column: 3 / 5;

background-color: rgb (243, 61, 29) ;

}

.equals: hover {

background-color: rgb (228, 39, 15) ;

}

Рендеринг элементов

Базовый файл для рендеринга в приложениях React — это index.js. Прежде чем мы пойдем дальше, убедитесь, что ваш index.jsвнешний вид выглядит следующим образом:

import React from «react»;

import ReactDOM from «react-dom»;

import App from «. /App»;

import «. /index.css»;

ReactDOM.render (

,

document.getElementById («root»)

) ;

Кроме того, давайте проверим index.cssи убедимся, что мы сбросили значения по умолчанию для paddingи margin, выберем какой-нибудь отличный шрифт (например, Montserrat в данном случае) и установим правильные правила для центрирования приложения в окне просмотра:

@import url («https: //fonts.googleapis.com/css2? family=Montserrat&display=swap») ;

* {

margin: 0;

padding: 0;

font-family: «Montserrat», sans-serif;

}

body {

height: 100vh;

display: flex;

align-items: center;

justify-content: center;

background-color: #fbb034;

background-image: linear-gradient (315deg, #fbb034 0%, #ffdd00 74%) ;

}

Наконец, давайте откроем основной файл App.jsи импортируем все компоненты, которые мы создали ранее:

import Wrapper from «. /components/Wrapper»;

import Screen from «. /components/Screen»;

import ButtonBox from «. /components/ButtonBox»;

import Button from «. /components/Button»;

const App = () => {

return (

<Button

className=""

value="0"

onClick={ () => {

console.log («Button clicked!») ;

}}

/>

 

 

) ;

};

export default App;

В приведенном выше примере мы визуализировали только один Buttonкомпонент.

Давайте создадим представление данных в виде массива в каркасе, чтобы мы могли отображать и отображать все кнопки в ButtonBox:

import Wrapper from «. /components/Wrapper»;

import Screen from «. /components/Screen»;

import ButtonBox from «. /components/ButtonBox»;

import Button from «. /components/Button»;

const btnValues = [

[«C», «+-«, «%», «/»],

[7, 8, 9, «X»],

[4, 5, 6, «-«],

[1, 2, 3, «+»],

[0, «.», «=»],

];

const App = () => {

return (

{

btnValues.flat ().map ((btn, i) => {

return (

<Button

key={i}

className={btn === «=" ? "equals»: ««}

value={btn}

onClick={ () => {

console.log (`${btn} clicked! `) ;

}}

/>

) ;

})

}

 

 

) ;

};

Проверьте свой терминал и убедитесь, что ваше приложение React все еще работает. Если нет, бегите, npm startчтобы запустить его снова.

Откройте браузер. Если вы следовали этому примеру, ваш текущий результат должен выглядеть так:

Дизайн приложения

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

Console.log

Определить состояния

Далее мы объявим переменные состояния, используя useStateхук React.

В частности, будет три состояния: numвведенное значение; sign, выбранный знак: и res, расчетное значение.

Чтобы использовать useStateхук, мы должны сначала импортировать его в App.js:

import React, { useState } from «react»;

В Appфункции мы будем использовать объект для одновременной установки всех состояний:

import React, { useState } from «react»;

//...

const App = () => {

let [calc, setCalc] = useState ({

sign: «»,

num: 0,

res: 0,

}) ;

return (

//...

) ;

};

Функциональность

Наше приложение выглядит красиво, но в нем нет функциональности. В настоящее время он может выводить только значения кнопок в консоль браузера. Давайте исправим это!

Начнем с Screenкомпонента. Установите следующую условную логику в valueprop, чтобы она отображала введенное число (если число введено) или вычисленный результат (если нажата кнопка равенства).

Для этого мы будем использовать встроенный тернарный оператор JS, который в основном является ярлыком для ifоператора, принимающего выражение и возвращающего значение после?, если выражение истинно, или после,: если выражение ложно:

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

import React, { useState } from «react»;

//...

const App = () => {

//...

return (

{btnValues.flat ().map ((btn, i) => {

return (

<Button

key={i}

className={btn === «=" ? "equals»: ««}

value={btn}

onClick={

btn === «C»

? resetClickHandler

: btn === «+-«

? invertClickHandler

: btn === «%»

? percentClickHandler

: btn === «=»

? equalsClickHandler

: btn === «/» || btn === «X» || btn === «-«|| btn === «+»

? signClickHandler

: btn === «.»

? commaClickHandler

: numClickHandler

}

/>

) ;

}) }

 

 

) ;

};

Теперь мы готовы создать все необходимые функции.

numClickHandler

Функция numClickHandlerсрабатывает только при нажатии любой из цифровых кнопок (0–9). Затем он получает значение Buttonи добавляет его к текущему numзначению.

Это также позволит убедиться, что:

целые числа не начинаются с нуля

перед запятой нет кратных нулей

формат будет «0». если «.» нажимается первым

числа вводятся длиной до 16 целых чисел

import React, { useState } from «react»;

//...

const App = () => {

//...

const numClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

if (calc.num.length < 16) {

setCalc ({

...calc,

num:

calc.num === 0 && value === «0»

? «0»

: calc.num% 1 === 0

? Number (calc.num + value)

: calc.num + value,

res:! calc.sign? 0: calc.res,

}) ;

}

};

return (

//...

) ;

};

запятаяClickHandler

Функция commaClickHandlerзапускается, только если. нажата десятичная точка (). Он добавляет десятичную точку к текущему numзначению, превращая его в десятичное число.

Это также гарантирует, что кратные десятичные точки невозможны.

Примечание. Я назвал функцию обработки «commaClickHandler», потому что во многих частях мира целые и десятичные числа разделяются запятой, а не десятичной точкой.

// numClickHandler function

const commaClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

setCalc ({

...calc,

num:! calc.num.toString ().includes («.»)? calc.num + value: calc.num,

}) ;

};

signClickHandler

Функция signClickHandlerзапускается, когда пользователь нажимает +, –, * или /. Конкретное значение затем устанавливается как текущее signзначение в calcобъекте.

Это также гарантирует, что повторные вызовы не повлияют:

// commaClickHandler function

const signClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

setCalc ({

...calc,

sign: value,

res:! calc.res && calc.num? calc.num: calc.res,

num: 0,

}) ;

};

equalsClickHandler

Функция equalsClickHandlerвычисляет результат при нажатии кнопки равенства (=). Расчет производится на основе текущего numи resзначения, а также signвыбранного (см. mathфункцию).

Возвращенное значение затем устанавливается как новое resдля дальнейших вычислений.

Это также позволит убедиться, что:

нет эффекта на повторные вызовы

пользователи не могут делить на 0

// signClickHandler function

const equalsClickHandler = () => {

if (calc.sign && calc.num) {

const math = (a, b, sign) =>

sign === «+»

? a + b

: sign === «-«

? a — b

: sign === «X»

? a * b

: a / b;

setCalc ({

...calc,

res:

calc.num === «0» && calc.sign === «/»

? «Can’t divide with 0»

: math (Number (calc.res), Number (calc.num), calc.sign),

sign: «»,

num: 0,

}) ;

}

};

инвертироватьClickHandler

Функция invertClickHandlerсначала проверяет, есть ли какое-либо введенное значение (num) или вычисленное значение (res), а затем инвертирует их, умножая на -1:

// equalsClickHandler function

const invertClickHandler = () => {

setCalc ({

...calc,

num: calc.num? calc.num * -1: 0,

res: calc.res? calc.res * -1: 0,

sign: «»,

}) ;

};

процентClickHandler

Функция percentClickHandlerпроверяет наличие введенного значения (num) или вычисленного значения (res), а затем вычисляет процентное значение с помощью встроенной Math.powфункции, которая возвращает основание в степени:

// invertClickHandler function

const percentClickHandler = () => {

let num = calc.num? parseFloat (calc.num): 0;

let res = calc.res? parseFloat (calc.res): 0;

setCalc ({

...calc,

num: (num /= Math.pow (100, 1)),

res: (res /= Math.pow (100, 1)),

sign: «»,

}) ;

};

resetClickHandler

Функция resetClickHandlerпо умолчанию использует все начальные значения calc, возвращая calcсостояние, которое было при первом отображении приложения «Калькулятор»:

// percentClickHandler function

const resetClickHandler = () => {

setCalc ({

...calc,

sign: «»,

num: 0,

res: 0,

}) ;

};

Форматирование ввода

Последнее, что нужно сделать, чтобы завершить список функций во введении, — реализовать форматирование значений. Для этого мы могли бы использовать модифицированную строку Regex, опубликованную Emissary:

const toLocaleString = (num) =>

String (num).replace (/ (? <! \... *) (\d) (?= (?: \d{3}) + (?: \. |$))/g, «$1») ;

По сути, он берет число, форматирует его в строковый формат и создает разделители пробелов для знака тысячи.

Если мы обращаем процесс и хотим обработать строку чисел, сначала нам нужно удалить пробелы, чтобы позже мы могли преобразовать ее в число. Для этого вы можете использовать эту функцию:

const removeSpaces = (num) => num.toString ().replace (/\s/g, «») ;

Вот код, в котором вы должны включить обе функции:

import React, { useState } from «react»;

//...

const toLocaleString = (num) =>

String (num).replace (/ (? <! \... *) (\d) (?= (?: \d{3}) + (?: \. |$))/g, «$1») ;

const removeSpaces = (num) => num.toString ().replace (/\s/g, «») ;

const App = () => {

//...

return (

//...

) ;

};

Ознакомьтесь со следующим разделом с полным кодом о том, как добавить toLocaleStringи removeSpacesк функциям обработчика для Buttonкомпонента.

Собираем все вместе

Если вы следовали всем инструкциям, весь App.jsкод должен выглядеть так:

import React, { useState } from «react»;

import Wrapper from «. /components/Wrapper»;

import Screen from «. /components/Screen»;

import ButtonBox from «. /components/ButtonBox»;

import Button from «. /components/Button»;

const btnValues = [

[«C», «+-«, «%», «/»],

[7, 8, 9, «X»],

[4, 5, 6, «-«],

[1, 2, 3, «+»],

[0, «.», «=»],

];

const toLocaleString = (num) =>

String (num).replace (/ (? <! \... *) (\d) (?= (?: \d{3}) + (?: \. |$))/g, «$1») ;

const removeSpaces = (num) => num.toString ().replace (/\s/g, «») ;

const App = () => {

let [calc, setCalc] = useState ({

sign: «»,

num: 0,

res: 0,

}) ;

const numClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

if (removeSpaces (calc.num).length < 16) {

setCalc ({

...calc,

num:

calc.num === 0 && value === «0»

? «0»

: removeSpaces (calc.num)% 1 === 0

? toLocaleString (Number (removeSpaces (calc.num + value)))

: toLocaleString (calc.num + value),

res:! calc.sign? 0: calc.res,

}) ;

}

};

const commaClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

setCalc ({

...calc,

num:! calc.num.toString ().includes («.»)? calc.num + value: calc.num,

}) ;

};

const signClickHandler = (e) => {

e.preventDefault () ;

const value = e.target.innerHTML;

setCalc ({

...calc,

sign: value,

res:! calc.res && calc.num? calc.num: calc.res,

num: 0,

}) ;

};

const equalsClickHandler = () => {

if (calc.sign && calc.num) {

const math = (a, b, sign) =>

sign === «+»

? a + b

: sign === «-«

? a — b

: sign === «X»

? a * b

: a / b;

setCalc ({

...calc,

res:

calc.num === «0» && calc.sign === «/»

? «Can’t divide with 0»

: toLocaleString (

math (

Number (removeSpaces (calc.res)),

Number (removeSpaces (calc.num)),

calc.sign

)

),

sign: «»,

num: 0,

}) ;

}

};

const invertClickHandler = () => {

setCalc ({

...calc,

num: calc.num? toLocaleString (removeSpaces (calc.num) * -1): 0,

res: calc.res? toLocaleString (removeSpaces (calc.res) * -1): 0,

sign: «»,

}) ;

};

const percentClickHandler = () => {

let num = calc.num? parseFloat (removeSpaces (calc.num)): 0;

let res = calc.res? parseFloat (removeSpaces (calc.res)): 0;

setCalc ({

...calc,

num: (num /= Math.pow (100, 1)),

res: (res /= Math.pow (100, 1)),

sign: «»,

}) ;

};

const resetClickHandler = () => {

setCalc ({

...calc,

sign: «»,

num: 0,

res: 0,

}) ;

};

return (

{btnValues.flat ().map ((btn, i) => {

return (

<Button

key={i}

className={btn === «=" ? "equals»: ««}

value={btn}

onClick={

btn === «C»

? resetClickHandler

: btn === «+-«

? invertClickHandler

: btn === «%»

? percentClickHandler

: btn === «=»

? equalsClickHandler

: btn === «/» || btn === «X» || btn === «-«|| btn === «+»

? signClickHandler

: btn === «.»

? commaClickHandler

: numClickHandler

}

/>

) ;

}) }

 

 

) ;

};

export default App;

Заключительные примечания

Поздравляем! Вы создали полнофункциональное и стильное приложение. Надеюсь, вы узнали кое-что в процессе!

Демо

Некоторые дополнительные идеи для вас могут заключаться в добавлении некоторых научных функций или реализации памяти со списком предыдущих вычислений.

Если у вас есть какие-либо отчеты об ошибках или пожелания, не стесняйтесь оставлять их в репозитории GitHub. Если вам понравился проект, не стесняйтесь отметить его звездочкой.

3D-печать5GABC-анализAndroidAppleAppStoreAsusCall-центрChatGPTCRMDellDNSDrupalExcelFacebookFMCGGoogleHuaweiInstagramiPhoneLinkedInLinuxMagentoMicrosoftNvidiaOpenCartPlayStationPOS материалPPC-специалистRuTubeSamsungSEO-услугиSMMSnapchatSonyStarlinkTikTokTwitterUbuntuUp-saleViasatVPNWhatsAppWindowsWordPressXiaomiYouTubeZoomАвдеевкаАктивные продажиАкцияАлександровск ЛНРАлмазнаяАлчевскАмвросиевкаАнализ конкурентовАнализ продажАнтимерчандайзингАнтрацитАртемовскАртемовск ЛНРАссортиментная политикаБелгородБелицкоеБелозерскоеБердянскБизнес-идеи (стартапы)БрендБрянкаБукингВахрушевоВендорВидеоВикипедияВирусная рекламаВирусный маркетингВладивостокВнутренние продажиВнутренний маркетингВолгоградВолновахаВоронежГорловкаГорнякГорскоеДебальцевоДебиторкаДебиторская задолженностьДезинтермедитацияДзержинскДивизионная система управленияДизайнДимитровДирект-маркетингДисконтДистрибьюторДистрибьюцияДобропольеДокучаевскДоменДружковкаЕкатеринбургЕнакиевоЖдановкаЗапорожьеЗимогорьеЗолотоеЗоринскЗугрэсИжевскИловайскИрминоКазаньКалининградКировскКировскоеКомсомольскоеКонстантиновкаКонтент-маркетингКонтент-планКопирайтингКраматорскКрасноармейскКрасногоровкаКраснодарКраснодонКраснопартизанскКрасный ЛиманКрасный ЛучКременнаяКураховоКурскЛисичанскЛуганскЛутугиноМакеевкаМариупольМаркетингМаркетинговая информацияМаркетинговые исследованияМаркетинговый каналМаркетинг услугМаркетологМарьинкаМедиаМелекиноМелитопольМенеджментМерчандайзерМерчандайзингМиусинскМолодогвардейскМоскваМоспиноНижний НовгородНиколаевНиколаевкаНишевой маркетингНовоазовскНовогродовкаНоводружескНовосибирскНумерическая дистрибьюцияОдессаОмскОтдел маркетингаПартизанский маркетингПервомайскПеревальскПетровскоеПлата за кликПоисковая оптимизацияПопаснаяПравило ПаретоПривольеПрогнозирование продажПродвижение сайтов в ДонецкеПроизводство видеоПромоПромоушнПрямой маркетингРабота для маркетологаРабота для студентаРазработка приложенийРаспродажаРегиональные продажиРекламаРеклама на асфальтеРемаркетингРетро-бонусРибейтРитейлРовенькиРодинскоеРостов-на-ДонуРубежноеСамараСанкт-ПетербургСаратовСватовоСвердловскСветлодарскСвятогорскСевастопольСеверодонецкСеверскСедовоСейлз промоушнСелидовоСимферопольСинергияСколковоСлавянскСнежноеСоздание сайтов в ДонецкеСоледарСоциальные сетиСочиСтаробельскСтаробешевоСтахановСтимулирование сбытаСуходольскСчастьеТелемаркетингТельмановоТираспольТорговый представительТорезТрейд маркетингТрейд промоушнТюменьУглегорскУгледарУкраинскХабаровскХарцызскХерсонХостингЦелевая аудиторияЦифровой маркетингЧасов ЯрЧелябинскШахтерскЮжно-СахалинскЮнокоммунаровскЯндексЯсиноватая