Идея проекта
Для моего последнего школьного проекта в школе Flatiron я создал приложение под названием Внимательный ребенок — простое приложение, позволяющее мамам проводить моменты осознанности со своими детьми. Практика осознанности может помочь детям замечать положительные стороны и развивать чувство признательности и благодарности. Пользователи могут щелкнуть категорию, которая приведет к видео с осознанием активности в этой конкретной категории. Если пользователи хотят видеть все 3 категории, они могут сделать это, а также подписаться на информационный бюллетень приложения.
Структура проекта
Шаг 1: Настройка API Rails
API Rails должен обеспечивать сохранение данных. Итак, вот некоторые настройки, которые я создал для своего бэкэнда, прежде чем запускать свой интерфейс с React.
Ассоциации
Категория
has_many :activities
Деятельность
принадлежит_к: категория
Настройка моделей
rails g resource Название категории:string — no-test-framework
rails g resource Название действия:string description:string category_id:integer url:string — no -тест-фреймворк
создал seed.file
Я использовал файл
db/seeds.rb
, потому что он предлагает простой механизм заполнения пустой базы данных значениями по умолчанию.
Скачать Cors
Обеспечивает поддержку общего доступа к ресурсам между источниками (CORS).
Созданные действия
Действия
Категории
Добавлен сериализатор
ActiveModel::Serializer — Сериализатор облегчает отношения, созданные в бэкэнде, а затем транслирует их во внешний интерфейс.
Обратите внимание, что контроллер находится под app/controllers/api/v1
, потому что я управляю версиями своего API. Это хорошая практика, позволяющая избежать критических изменений и обеспечить некоторую обратную совместимость с API. См. пример ниже.
namespace :api do namespace :v1 do resources :categories do resources :activities end end end
Шаг 2: Создать-реагировать-приложение
Я использовал генератор create-react-app
, чтобы начать свой проект. В среде будет все необходимое для создания одностраничного приложения React. Настройте файлы действий, компонентов, контейнеров и редукторов.
Шаг 3: React-Redux
В проект добавлен React-Redux. Я использовал некоторые компоненты и функции, чтобы связать React и Redux вместе: Store, Provider и Connect.
Шаблон Redux, в котором хранилище отправляет действие редюсеру, который затем берет эту информацию в объекте действия для внесения изменений в состояние, что, в свою очередь, вызывает повторную визуализацию компонентов с новыми данными. -Утюг
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux' import store from './store.js' import App from './App'; import 'bootstrap/dist/css/bootstrap.min.css'; ReactDOM.render( <Provider store={ store }> <App /> </Provider>, document.getElementById('root') );
Промежуточное ПО Redux-Thunk
Когда пользователь нажимает на кнопку, мы вызываем функцию handleChange()
. Это вызывает нашего создателя действия, функцию fetchCategories()
. Затем создатель действия обращается к API и возвращает действие с нашими данными, которые затем обновляют состояние через редьюсер. Запрос fetch()
возвращает нечто, называемое Promise. Объект Promise — это объект, представляющий некоторое значение, которое будет доступно позже. Мы можем получить доступ к данным, когда обещание «разрешится» и станет доступным, привязав функцию .then()
к нашему вызову fetch()
. См. пример ниже.
export function fetchCategories () { return (dispatch) => { fetch(‘http://localhost:3000/api/v1/categories') .then(resp => resp.json()) .then(categories => dispatch({ type: ‘FETCH_CATEGORIES’, payload: categories })) } } ____________________________________________________________________ ...imports goes here... class Newsletter extends React.Component{ ...more code goes here.... //update state with setState handleChange = (event) => { this.setState({ email: event.target.value }); } ...more code goes here.... export default connect(null,{addEmail})(Newsletter)
Обратите внимание, что веб-запросы в JavaScript являются асинхронными.
Это означает, что если мы сделаем веб-запрос в первой строке нашей функции fetchCategories()
. При извлечении данных из API мы сталкиваемся с проблемой, когда создатель действия возвращает действие до получения данных. Чтобы решить эту проблему, я использовал промежуточное ПО под названием Thunk.
Помните, Thunk позволяет нам возвращать функцию внутри создателя действия вместо простого объекта JavaScript. Эта возвращенная функция получает функцию отправки хранилища, и с ее помощью мы можем отправлять несколько действий: одно для перевода состояния в состояние загрузки, а другое для обновления хранилища возвращенными данными. Чтобы использовать Thunk, следуйте инструкциям по установке пакета NPM.
Шаг 4: Маршрутизатор
Одним из требований для этого проекта было использование правильной маршрутизации RESTful, такой как React Router.
React Router позволяет нам создать одностраничное веб-приложение с навигацией без обновления страницы при навигации пользователя. React Router использует структуру компонентов для вызова компонентов, которые отображают соответствующую информацию.
Я добавил Router в index.js, обертывающий дочерние компоненты ‹APP/›, и импортировал приведенные ниже.
import { BrowserRouter as Router, Route, Switch} from 'react-router-dom'; import 'bootstrap/dist/css/bootstrap.min.css'; class App extends React.Component{ render() { return ( <Router> <div className="App"> <Header/> <Switch> <Route exact path='/categories' component= {CategoriesContainer}/> <Route exact path='/newsletter' component={Newsletter}/> <Route path='/categories/:id/activity' component={ActivitiesContainer}/> <Route exact path='/' component={Home}/> <Route path="*" component={NotFound} /> </Switch> </div> </Router> ); } } export default App;
Компоненты
Я использовал компонент более высокого порядка, такой как connect(), в моих 2 компонентах-контейнерах. Мои7 презентационных компонентов не имеют состояния и принимают реквизиты из компонента-контейнера ине взаимодействуют с хранилищем Redux.
Я использовал функциональные компоненты для компонентов, мне не нужно было состояние или жизненный цикл, которые доступны для компонентов класса.
Вот короткая демонстрация моего приложения.
Спасибо, что прочитали этот пост в блоге, и большое спасибо Flatiron School.
Если у вас есть какие-либо комментарии или отзывы, пожалуйста, дайте мне знать. Вы можете увидеть весь код этого проекта на GitHub repo.