Сегодня мы будем использовать самые современные практики React и создадим простое приложение, полностью на функциональных компонентах, с использованием хуков.
Чтобы не утомлять вас долгими рассказами о том. что это за приложение, я скажу так, что это поиск рецептов, которые мы получаем со стороннего сайта. Лучше одни раз увидеть - здесь.
Нам потребуется сайт, который предоставит нам данные. Для этой цели мы будем использовать edamam.com. Для использования этого сервиса вам потребуется регистрация. Она простая. На сайте переходите на вкладку "API Developer Portal". Далее, вверху слева, выбираете "APIs" и в выпадающем меню - "Recipe Search API". Все, как показано на картинке, ниже.
На вкладке "Developer", выбираете поле нажимаете - "start now".
выбираете имя пользователя, пароль, вводите адрес почты и ...все попадаете на вкладку "Dashboard" вашего приложения, где нас будут интересовать только два поля: Application ID и Application Keys .
Нам потребуется пример запроса. Для этого переходим в раздел "Документы" разработчиков и в середине страницы находим пример для
Все как на картинке ниже:
Скопируем его полностью.
Теперь, развернем наше приложение на основе create-react-app. После обновления до третей версии, это приложение перестало запускаться "из коробки" полностью, из-за проблем со скриптами. Для того, чтобы не переустанавливать все после создания приложения я использую свою заготовку — cra3-boilerplate. Там я достаточно подробно описал, как все это развернуть на рабочем компе.
Производим обычные изменения в файле App.js переписываем компонент на функцию и удаляем все внутри метода
Внутри функции, создадим три константы (
Для того, чтобы лучше понять, как работают некоторые хуки в реакт, мы сделаем небольшое отступление. Вы можете это просто причитать, для сведения.
Представим. что у нас в приложении есть некий счетчик кликов. Он подключен вне формы, ну например - к заголовку в который и будем выводить данные этого счетчика. Счетчик будет меняться по клику.
Для сохранения данных в приложении, мы будем использовать хук -
Посмотрите в браузер и убедитесь, что все работает.
Теперь, добавим в наше приложение еще один полезный хук -
Этот хук принимает функцию. В ней мы просто выведем в консоль сообщение, что данный хук запущен.
Теперь, если посмотреть в консоль приложения, то мы увидим, что этот хук запускается по каждому клику на счетчик.
Для того, чтобы задать ему правильную работу, мы можем передать в функцию этого хука пустой массив, и получим работу
На фото видно, что не смотря на то, что мы кликнули на счетчик уже десяток раз, но хук запустился только однажды - при загрузке документа.
Если мы передадим туда переменную, которую мы хотим отслеживать, то мы можем просто написать так:
Таким образом, запуск этого эффекта будет сопровождать каждое изменение значения счетчика —
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Counter with useEffect"
ci -m - здесь и всегда в этом блоге обозначают коммит.
Вернемся в наше приложение и продолжим.
Для запроса к серверу, мы отойдем от обычного использования обещаний -
Для сохранения данных, которые мы получим, будем использовать хук состояния -
Забегая немного вперед, я скажу. что данные нам приходят в виде массива объектов. В этом легко убедиться. если просто вывести их вначале в консоль. Но я, зная это, сразу создам эти переменные "состояния". В обычной практике, все таки стоит убедиться в этом при получении данных.
Для отправки запроса создадим отдельную функцию -
Ничего особенно нового. Для запроса, мы использовали строку, которую ранее сохраняли в переменную -
Для отправки запроса на сервер, мы будем использовать хук -
Кстати, бесплатный лимит на запросы на этом сервисе составляет 10 запросов в минуту.
Здесь мы видим, что к нам пришли данные в виде массива объектов.
Каждый отдельный элемент содержит следующие поля:
А все рецепты приходят внутри поля
Потому мы можем смело сохранять не поле
Здесь я приведу полностью файл App.js на этом этапе:
App.js
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "getRecipes with async / await fetch request and output in console"
Это будет тоже простой функциональный компонент, в который мы передадим данные, и задачей которого будет вывод данных на страницу.
Ниже, я приведу его полностью, так легче объяснять.
Recipes.js
Здесь мы, путем деструктуризации, получаем из
Для стилизации добавили классы.
Это конечная версия нашего компонента, но на этапе его создания, я просто выводил статические данные, и не принимал
Да, и не забудьте импортировать ваш вновь созданный компонент, в App.js
И ниже формы в рендере, выведем с помощью метода
В этом коде я уже передал нужные данные компоненту, но на этапе создания я этого не делал и потому получал простой вывод статического компонента N-ное количество раз.
Еще важно отметить необходимость создания ключа для вывода компонентов списком. Споры о ключах еще ведутся в сообществе, но для них мы можем использовать любые статические данные, которые будут помогать определять реакту нужный элемент в дереве компонентов. На этот раз я использовал
На картинке выше, вы видите. что компонент вывелся столько же раз, сколько пришло элементов с данными.
Если посмотреть в консоль, то можно четко увидеть структуру, полученных данных и определиться с возможностью их вывода на страницу (передачи в компонент Recipes.js )
Как только мы определились с данными и решили, что мы будем выводить в компоненте, то (код выше) мы получим следующую картину в браузере:
Таким образом, мы получили данные и вывели их на страницу.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "output of recipes to the page"
Для создания динамики, нам нужно заменить это поле данными, которые пользователь будет вводить в поле
Для сохранения данных ввода пользователя, нам потребуется еще две переменные "состояния", которые мы создадим использую, также как и ранее -
Теперь нам нужно получить эти данные и записать их в эту переменную. Для этого создадим функцию
Как видно из кода выше, функция принимает объект события -
setSearch(e.target.value)
В консоль выводим данную переменную, в которую поместили данные пользователя.
Теперь, подключим эту функцию к инпуту на событие изменения -
Посмотрим на то, что получилось в консоль
Там мы увидим все буквы введенные в инпут в соответствующем порядке.
Сейчас у нас есть приложение, которое сохраняет данные введенные пользователем в переменную, но если мы передадим эту переменную
По умолчанию, там и будет та самая курица -
Для того, чтобы полученные данные от пользователя из переменной
Да, вот этим
Теперь в
В тело запроса, в функции
Таким образом, мы сделали так, что все изменения, которые возникают в переменной, которая хранит состояние ввода пользователя, передаются в запрос, только тогда. когда пользователь нажимает на кнопку, или вводит Enter с клавиатуры.
App.js
В браузере мы сможем теперь спокойно отправлять запросы и получать нужные данные
На фото выше, видно, что данные с сервера получены, только после полного ввода и отправки запроса кнопкой.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Searching on click button"
И меленькое дополнение. Для очистки поля ввода после нажатия кнопки, мы можем добавить в самый конец функции
Таким образом мы изменили переменную "состояния"
В файле App.js мы передадим эти данные, как пропсы для нашего компнента Recipes.js
В компоненте Recipes.js мы получим их деструктуризацией и выведем с помощью
Посмотрим в браузере:
Ингредиенты каждого компонента выводятся в виде списка.
Теперь нам нужно добавить немного стилей, для привлекательности нашего приложения.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Output ingradients list and clean search input"
Более подробно о стилях в Реакт я писал в посте - 5 способов написания стилей CSS в React.js
App.css
Для файла Recipes.js я создал отдельный файл recipes.module.css в котором написал следующее.
recipes.module.css
В файле Recipes.js я их подключил:
Модули очень просты в использовании и приятны для многократного применения.
Надеюсь, что я вас не утомил подробностями. Буду рад вашим отзывам.
Это только основа приложения. Вы можете его изменить и дополнить, например - выводом на страницу отдельного рецепта, собственными стилями, и много чем еще.
Happy codding!
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Add styles and styles module"
Если интересно, то заходите в группу в facebook Facebook-Group, подписывайтесь на мой канал по ссылке ниже, или на мою страницу в facebook Yaroslav Web-Master
Чтобы не утомлять вас долгими рассказами о том. что это за приложение, я скажу так, что это поиск рецептов, которые мы получаем со стороннего сайта. Лучше одни раз увидеть - здесь.
Нам потребуется сайт, который предоставит нам данные. Для этой цели мы будем использовать edamam.com. Для использования этого сервиса вам потребуется регистрация. Она простая. На сайте переходите на вкладку "API Developer Portal". Далее, вверху слева, выбираете "APIs" и в выпадающем меню - "Recipe Search API". Все, как показано на картинке, ниже.
На вкладке "Developer", выбираете поле нажимаете - "start now".
выбираете имя пользователя, пароль, вводите адрес почты и ...все попадаете на вкладку "Dashboard" вашего приложения, где нас будут интересовать только два поля: Application ID и Application Keys .
Нам потребуется пример запроса. Для этого переходим в раздел "Документы" разработчиков и в середине страницы находим пример для
GET
запроса:
curl "https://api.edamam.com/search?q=chicken&app_id=${YOUR_APP_ID}&app_key=${YOUR_APP_KEY}&from=0&to=3&calories=591-722&health=alcohol-free"
Все как на картинке ниже:
Скопируем его полностью.
Теперь, развернем наше приложение на основе create-react-app. После обновления до третей версии, это приложение перестало запускаться "из коробки" полностью, из-за проблем со скриптами. Для того, чтобы не переустанавливать все после создания приложения я использую свою заготовку — cra3-boilerplate. Там я достаточно подробно описал, как все это развернуть на рабочем компе.
Производим обычные изменения в файле App.js переписываем компонент на функцию и удаляем все внутри метода
render()
, именно внутри div className="App"
. Напишем вывод простой форму с импутом и кнопокйо отправки запроса для поиска. Зададим сразу классы, для стилизации элементов. Удаляем logo
и его импорт.
<form className="search-form"> <input className="search-bar" type="text" /> <button className="search-button" type="submit"> Search </button> </form>;
Внутри функции, создадим три константы (
APP_ID
, APP_KEY
и exampleRequest
), куда и запишем данные нашего приложения, полученные на сейте рецептов ранее.
Для того, чтобы лучше понять, как работают некоторые хуки в реакт, мы сделаем небольшое отступление. Вы можете это просто причитать, для сведения.
Коротко о работе useEffect
Представим. что у нас в приложении есть некий счетчик кликов. Он подключен вне формы, ну например - к заголовку в который и будем выводить данные этого счетчика. Счетчик будет меняться по клику.
<h1 onClick={() => setCounter(counter + 1)}>{counter}</h1>
Для сохранения данных в приложении, мы будем использовать хук -
useState
с начальным значением равным нулю.
const [counter, setCounter] = useState(0);
Посмотрите в браузер и убедитесь, что все работает.
Теперь, добавим в наше приложение еще один полезный хук -
useEffect
. С помощью этого хука мы будем отправлять запросы на сервер, как если бы мы использовали жизненный цикл — componentDidMount компонента с состоянием
Этот хук принимает функцию. В ней мы просто выведем в консоль сообщение, что данный хук запущен.
useEffect(() => { console.log("useEffect has been run"); });
Теперь, если посмотреть в консоль приложения, то мы увидим, что этот хук запускается по каждому клику на счетчик.
Для того, чтобы задать ему правильную работу, мы можем передать в функцию этого хука пустой массив, и получим работу
useEffect
, только при первом построении нашего приложения, то есть практически тоже самое. что componentDidMount
.
На фото видно, что не смотря на то, что мы кликнули на счетчик уже десяток раз, но хук запустился только однажды - при загрузке документа.
Если мы передадим туда переменную, которую мы хотим отслеживать, то мы можем просто написать так:
useEffect(() => { console.log("useEffect has been run"); }, [counter]);
Таким образом, запуск этого эффекта будет сопровождать каждое изменение значения счетчика —
counter
, а не любой другой переменной данного приложения.
import React from "react"; import "./App.css"; const App = () => { const APP_ID = "yourData Application-ID"; const APP_KEY = "yourData Application-Kyes"; const exampleRequest = `https://api.edamam.com/search?q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}`; const [counter, setCounter] = useState(0); useEffect(() => { console.log("useEffect has been run"); }, [counter]); return ( <div className="App"> <form className="search-form"> <input className="search-bar" type="text" /> <button className="search-button" type="submit"> Search </button> </form> <h1 onClick={() => setCounter(counter + 1)}>{counter}</h1> </div> ); }; export default App;
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Counter with useEffect"
ci -m - здесь и всегда в этом блоге обозначают коммит.
Вернемся в наше приложение и продолжим.
Получение данных и сохранение их в переменную
На этом этапе нашей задачей будет отправить запрос к сайту, который нам предоставил API, получить их и сохранить в "состояние". Для этого нам потребуется хук "состояния" -useState
, который мы импортируем из реакт.
Для запроса к серверу, мы отойдем от обычного использования обещаний -
Promuse
, а воспользуемся более удобным способом придания асинхронности запросу, с помощью - async / await
Об этом я много раз писал в этом блоге и вы можете найти посты перейдя по ссылке.
async / await в этом блоге.
Для сохранения данных, которые мы получим, будем использовать хук состояния -
useState
const [recipes, setRecipes] = useState([]);
Забегая немного вперед, я скажу. что данные нам приходят в виде массива объектов. В этом легко убедиться. если просто вывести их вначале в консоль. Но я, зная это, сразу создам эти переменные "состояния". В обычной практике, все таки стоит убедиться в этом при получении данных.
Для отправки запроса создадим отдельную функцию -
getRecipes
const getRecipes = async () => { const response = await fetch( `https://api.edamam.com/search?q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}` ); const data = await response.json() setRecipes(data) console.log(data) }
Ничего особенно нового. Для запроса, мы использовали строку, которую ранее сохраняли в переменную -
exampleRequest
. И сделали просто асинхронное получение данных, сохранение их в переменную "состояния" setRecipes(data)
и вывод их в консоль.
Для отправки запроса на сервер, мы будем использовать хук -
useEffect
, куда и передадим нашу функцию и пустой массив, для исключения повторных запросов к серверу.
Кстати, бесплатный лимит на запросы на этом сервисе составляет 10 запросов в минуту.
useEffect(() => { getRecipes() },[])
Здесь мы видим, что к нам пришли данные в виде массива объектов.
Каждый отдельный элемент содержит следующие поля:
А все рецепты приходят внутри поля
hits
Потому мы можем смело сохранять не поле
data
, а data.hits
. И тогда в консоли мы увидим:
Здесь я приведу полностью файл App.js на этом этапе:
App.js
import React, { useEffect, useState } from "react"; import "./App.css"; const App = () => { const APP_ID = "your_data_app_ID"; const APP_KEY = "your_data_app_keys"; useEffect(() => { getRecipes(); }, []); const getRecipes = async () => { const response = await fetch( `https://api.edamam.com/search?q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}` ); const data = await response.json(); console.log(data.hits); }; return ( <div className="App"> <form className="search-form"> <input className="search-bar" type="text" /> <button className="search-button" type="submit"> Search </button> </form> </div> ); }; export default App;
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "getRecipes with async / await fetch request and output in console"
Создание компонента для вывода отдельного элемента
Коль скоро, данные у нас получены и сохранены, то мы можем их вывести на страницу. Для этого создадим отдельный компонент - Recipes.js.Это будет тоже простой функциональный компонент, в который мы передадим данные, и задачей которого будет вывод данных на страницу.
Ниже, я приведу его полностью, так легче объяснять.
Recipes.js
import React from "react"; const Recipes = ({ title, calories, image }) => { return ( <div> <h1>{title}</h1> <p>{calories}</p> <img src={image} alt="" /> </div> ); }; export default Recipes;
Здесь мы, путем деструктуризации, получаем из
props
передаваемые значения, сразу же выводя их на страницу с помощью компонента.
Для стилизации добавили классы.
Это конечная версия нашего компонента, но на этапе его создания, я просто выводил статические данные, и не принимал
props
. Получилось то, что вы можете видеть на картинке ниже.
Да, и не забудьте импортировать ваш вновь созданный компонент, в App.js
import Recipes from './Recipes';
И ниже формы в рендере, выведем с помощью метода
map
, те данные, которые мы получили и сохранили в переменной recipes
<div className="recipes"> {recipes.map(recipe => ( <Recipes key={recipe.recipe.label} title={recipe.recipe.label} calories={recipe.recipe.calories} image={recipe.recipe.image} /> ))} </div>;
В этом коде я уже передал нужные данные компоненту, но на этапе создания я этого не делал и потому получал простой вывод статического компонента N-ное количество раз.
Еще важно отметить необходимость создания ключа для вывода компонентов списком. Споры о ключах еще ведутся в сообществе, но для них мы можем использовать любые статические данные, которые будут помогать определять реакту нужный элемент в дереве компонентов. На этот раз я использовал
key={recipe.recipe.label}
На картинке выше, вы видите. что компонент вывелся столько же раз, сколько пришло элементов с данными.
Если посмотреть в консоль, то можно четко увидеть структуру, полученных данных и определиться с возможностью их вывода на страницу (передачи в компонент Recipes.js )
Как только мы определились с данными и решили, что мы будем выводить в компоненте, то (код выше) мы получим следующую картину в браузере:
Таким образом, мы получили данные и вывели их на страницу.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "output of recipes to the page"
Создание поиска элементов для запроса с сервера.
В данный момент у нас в запросе передается строка, где просто прописано -chicken
const response = await fetch(
`https://api.edamam.com/search?q=chicken&app_id=${APP_ID}&app_key=${APP_KEY}`
);
Для создания динамики, нам нужно заменить это поле данными, которые пользователь будет вводить в поле
input
Для сохранения данных ввода пользователя, нам потребуется еще две переменные "состояния", которые мы создадим использую, также как и ранее -
useState
const [search, setSearch] = useState('');
Теперь нам нужно получить эти данные и записать их в эту переменную. Для этого создадим функцию
const updateSearch = e => { setSearch(e.target.value); console.log(search); }
Как видно из кода выше, функция принимает объект события -
e
из которого данные значения этого события - e.target.value
(а это и есть буква, введенная пользователем), мы записываем в переменную "состояния" - search
, как метод хука состояния - search
setSearch(e.target.value)
В консоль выводим данную переменную, в которую поместили данные пользователя.
Теперь, подключим эту функцию к инпуту на событие изменения -
onChange
onChange={updateSearch}
Посмотрим на то, что получилось в консоль
Там мы увидим все буквы введенные в инпут в соответствующем порядке.
Сейчас у нас есть приложение, которое сохраняет данные введенные пользователем в переменную, но если мы передадим эту переменную
search
непосредственно в тело запроса, на место chicken
, как показано выше, то мы получим отправку запроса при каждой нажатии буквы. Это не самый правильный путь.
Отправка запроса только после его полного ввода.
Поэтому, мы создадим еще пару переменных "состояния", в которых и будет находиться наш запрос, который и будем передавать в поле запроса.const [query, setQuery] = useState("chicken");
По умолчанию, там и будет та самая курица -
"chicken"
.
Для того, чтобы полученные данные от пользователя из переменной
search
и передать их, по клику на кнопку формы, в переменную запроса - query
, мы напишем такой код:
const getSearch = e => { e.preventDefault(); setQuery(search); }
Да, вот этим
e.preventDefault();
уберем всплытие события и перезагрузку страницы, потому как функция у нас будет срабатывать на событие onSubmit
самой формы:
<form onSubmit={getSearch} className="search-form">
Теперь в
useEffect
в качестве аргумента, передадим переменную - [query]
, как массив, за которой и будет следить реакт и при ее изменении делать запрос к серверу, то есть вызывать функцию получения данных:
useEffect(() => { getRecipes() },[query])
В тело запроса, в функции
getRecipes
, вместе цыпленка - , мы передадим переменную запроса -
const getRecipes = async () => {
const response = await fetch(
`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`
);
const data = await response.json()
setRecipes(data.hits)
console.log(data.hits)
}
Таким образом, мы сделали так, что все изменения, которые возникают в переменной, которая хранит состояние ввода пользователя, передаются в запрос, только тогда. когда пользователь нажимает на кнопку, или вводит Enter с клавиатуры.
App.js
import React, { useEffect, useState } from "react"; import Recipes from "./Recipes"; import "./App.css"; const App = () => { const APP_ID = "yourAPP-ID"; const APP_KEY = "yourAPP-Key"; const [recipes, setRecipes] = useState([]); const [search, setSearch] = useState(""); const [query, setQuery] = useState("chicken"); useEffect(() => { getRecipes(); }, [query]); const getRecipes = async () => { const response = await fetch( `https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}` ); const data = await response.json(); setRecipes(data.hits); console.log(data.hits); }; const updateSearch = e => { setSearch(e.target.value); console.log(search); }; const getSearch = e => { e.preventDefault(); setQuery(search); }; return ( <div className="App"> <form onSubmit={getSearch} className="search-form"> <input className="search-bar" value={search} type="text" onChange={updateSearch} /> <button className="search-button" type="submit"> Search </button> </form> {recipes.map(recipe => ( <Recipes key={recipe.recipe.label} title={recipe.recipe.label} calories={recipe.recipe.calories} image={recipe.recipe.image} /> ))} </div> ); }; export default App;
В браузере мы сможем теперь спокойно отправлять запросы и получать нужные данные
На фото выше, видно, что данные с сервера получены, только после полного ввода и отправки запроса кнопкой.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Searching on click button"
И меленькое дополнение. Для очистки поля ввода после нажатия кнопки, мы можем добавить в самый конец функции
getSearch
такую строку - setSearch('');
.
Таким образом мы изменили переменную "состояния"
search
на пустую строку, сразу после отправки запроса, тем саммым мы очистили форму.
Добавим данные для вывода на страницу.
Если посмотреть на те данные, которые к нам приходят с сервера, в консоли, то мы можем увидеть, что там есть графа инградиенты, которую мы можем легко вывести для отображения на странице.В файле App.js мы передадим эти данные, как пропсы для нашего компнента Recipes.js
<Recipes
key={recipe.recipe.label}
title={recipe.recipe.label}
calories={recipe.recipe.calories}
image={recipe.recipe.image}
ingredients={recipe.recipe.ingredients}
/>
В компоненте Recipes.js мы получим их деструктуризацией и выведем с помощью
map
.
import React from "react"; const Recipes = ({ title, calories, image, ingredients }) => { return ( <div> <h1>{title}</h1> <p>{calories}</p> <ol> {ingredients.map((ingredient, index) => ( <li key={index}>{ingredient.text}</li> ))} </ol> <img src={image} alt={title} /> </div> ); }; export default Recipes;
Посмотрим в браузере:
Ингредиенты каждого компонента выводятся в виде списка.
Теперь нам нужно добавить немного стилей, для привлекательности нашего приложения.
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Output ingradients list and clean search input"
Стилизация приложения.
О различных способах стилизации реакт--приложений, я многократно рассказывал в своих постах по реакту, на этот раз я остановлюсь только лишь на модуле стиля. Стили вы можете написать сами, как вам будет угодно. Для этого вы можете использовать готовые библиотеки. Я же просто добавил для файла App.js такие стили:Более подробно о стилях в Реакт я писал в посте - 5 способов написания стилей CSS в React.js
App.css
.App { min-height: 100vh; background-image: linear-gradient(45deg, #ff9a9e 0%, #fad0c4 99%, #fad0c4 100%); } .search-form { min-height: 10vh; display: flex; justify-content: center; align-items: center; } .search-bar { width: 50%; border: none; padding: 10px; } .search-button { background-color: lightcoral; border: none; padding: 10px 20px; color: white; } .recipes { display: flex; justify-content: space-around; flex-wrap: wrap; }
Для файла Recipes.js я создал отдельный файл recipes.module.css в котором написал следующее.
recipes.module.css
.recipe { border-radius: 10px; box-shadow: 0px 5px 20px rgb(71, 71, 71); margin: 20px; display: flex; flex-direction: column; justify-content: space-around; background-color: #fff; align-items: center; min-width: 40%; } .img { width: 100px; height: 100px; border-radius: 50%; margin-bottom: 2%; }
В файле Recipes.js я их подключил:
import React from "react"; import style from "./recipe.module.css"; const Recipes = ({ title, calories, image, ingredients }) => { return ( <div className={style.recipe}> <h1>{title}</h1> <p>{calories}</p> <ol> {ingredients.map((ingredient, index) => ( <li key={index}>{ingredient.text}</li> ))} </ol> <img className={style.img} src={image} alt={title} /> </div> ); }; export default Recipes;
Модули очень просты в использовании и приятны для многократного применения.
Надеюсь, что я вас не утомил подробностями. Буду рад вашим отзывам.
Это только основа приложения. Вы можете его изменить и дополнить, например - выводом на страницу отдельного рецепта, собственными стилями, и много чем еще.
Happy codding!
Все изменения на этом этапе, вы можете посмотреть в моем репозитории на gitHub — react-recipe-edamam
ci -m "Add styles and styles module"
Если интересно, то заходите в группу в facebook Facebook-Group, подписывайтесь на мой канал по ссылке ниже, или на мою страницу в facebook Yaroslav Web-Master
Комментариев нет:
Отправить комментарий