Для своего последнего проекта портфолио я создал приложение под названием I Had That! , чтобы пользователи могли хранить коллекцию детских игрушек, которые у них были. Увидев ретро-игрушки, вы возвращаетесь в прошлое, и вы начинаете вспоминать, как весело проводили время, играя со своими игрушками. В начале 80-х у меня был Commodore VIC-20 (не такой крутой, как Commodore 64 более высокого уровня), который научил меня языку программирования BASIC. Он подключился к нашему телевизору, и если я повернул канал на 3, телевизор стал монитором!

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

1. Rails API

Первым шагом в создании этого приложения является настройка серверной части Rails.

Модели и ассоциации

Бэкэнд реализует модель пользователя, модель игрушки и объединенную таблицу между пользователем и игрушкой, называемую ToyOwnership.

  1. Пользователь
has_many :toy_ownerships, dependent: :destroy
has_many :toys, through: :toy_ownerships

2. Игрушка

has_many :toy_ownerships, dependent: :destroy
has_many :users, through: :toy_ownerships

3. ToyOwnership

belongs_to :user
belongs_to :toy

CORS

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

Для этого проекта config/initializers/cors.rb настроен так, чтобы разрешать запросы от http: // localhost: 3001 и разрешать [:get, :post, :patch, :delete] запросы к API.

Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins 'http://localhost:3001'
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
credentials: true
end
end

Сериализатор

Активный сериализатор модели используется для создания объектов JSON. Это позволяет мне выбирать только ту информацию, которую я хочу отображать.

2. Приложение React

Чтобы быстро освоить React, я начал свой проект с помощью генератора create-react-app. Он предоставляет стартер приложения React для создания одностраничного приложения React.

3. React-Redux

React-Redux позволяет вашим компонентам React читать данные из хранилища Redux и отправлять действия в хранилище для обновления данных.

<Provider /> делает магазин Redux доступным для остальной части приложения.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store'
ReactDOM.render(
<Provider store={ store }>
<App />
</Provider>, document.getElementById('root'));

React Redux также предоставляет функцию connect, которая позволяет вам подключить ваш компонент к магазину.

mapStateToProps используется для выбора части данных из хранилища, которая нужна подключенному компоненту. Он возвращает простой объект, содержащий данные, необходимые компоненту. В этом случае он возвращает объекты user и toys.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import ToyCard from '../components/ToyCard';
import { Card, Divider } from 'semantic-ui-react';
class MyStuff extends Component {
...
}
const mapStateToProps = (state) => {
  return ({
   user: state.currentUser,
   toys: state.toys
  })
}
export default connect(mapStateToProps)(MyStuff);

4. Промежуточное ПО Redux-Thunk

Redux-Thunk - это промежуточное программное обеспечение, используемое для обработки асинхронных действий в Redux. По умолчанию создатели действий Redux не поддерживают асинхронные действия, такие как выборка данных, поэтому нам нужно использовать Redux Thunk. Использование этого промежуточного программного обеспечения позволяет избежать проблемы, когда создатель действия возвращает действие до получения данных.

// Asynchronous action creators
export const login = credentials => {
   return dispatch => {
      return fetch("http://localhost:3000/api/v1/login",
          { credentials: "include",
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(credentials)
          })
      
    .then(r => r.json())
    .then(user => {
       if (user.error) {
          alert(user.error)
       } else {
         dispatch(setCurrentUser(user))
         dispatch(getMyToys(user))
       }
    })
  }
}

5. Маршрутизатор

React Router позволяет одностраничным приложениям (SPA) перемещаться по нескольким представлениям без перезагрузки всей страницы.

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

import { BrowserRouter as Router, Route, Switch} from 'react-router-dom';
...
class App extends React.Component {
 ...
render() {
let loggedIn=this.props.currentUser.username
return (
 <div>
 <Router>
 <div className="App">
 <NavBar />
 <h3>I HAD THAT!</h3>
 { loggedIn ? <Logout /> : <div> <Login /> <Signup /> </div> }
 { loggedIn ? <ToyForm /> : ""}
 <Switch>
  <Route exact path="/" component={Home}/>
  <Route path="/toys" component={Toys} />
  <Route path="/myStuff" component={MyStuff} />
  <Route path="/about" component={About}/>
 </Switch>
 <Divider />
<Footer />
</div>
</Router>
</div>
  );
 }
}

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