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

Redux - это технология управления состоянием, созданная командой React. Он значительно очищает состояние вашего приложения, создавая глобальное «хранилище», в котором могут храниться все состояния и изменения состояний, независимо от того, в каком файле или на какой странице вы находитесь. Redux также помогает разработчикам избегать поддержки Drill, поскольку родительским компонентам больше не нужно напрямую передавать данные своим детям, внукам, правнукам и т. д. через реквизиты. Давайте посмотрим, что это означает, с помощью экземпляра create-user.

Во-первых, нам понадобится форма регистрации, чтобы наш пользователь мог создать учетную запись.

// src/Components/SignupForm.js //
import {createUser} from '../Actions/userActions.js'
import React from 'react'
import {connect} from 'react-redux'
class SignupForm extends React.Component{
   
   state = {
     username: '',
     password: '',
   }
   handleChange = e => {
     this.setState({
       [e.target.name]: e.target.value
     })    
   }        
   handleSubmit = e => {
     e.preventDefault()
     this.props.createUser(this.state)
   }
   render(){
      return(
          <form onSubmit={this.handleSubmit}>
            <input type="text" name="username"
             placeholder="Username"
             value={this.state.username} 
             onChange={this.handleChange}/>
            <input type="password" name="password" 
             placeholder="Enter Password" 
             value={this.state.password}
             onChange={this.handleChange}/>
            <input type="submit" value="Signup"/>}
          </form>
        )
    }
}
export default connect(null, createUser)(SignupForm)

Давайте рассмотрим это и посмотрим, где Redux был вставлен в нашу форму React.

import {createUser} from '../Actions/userActions.js'

Бизнес createUser - это действие, которое мы создали в файле с именем userActions.js и импортируем в наш файл RegistrationForm.js. Поскольку мы импортировали его, теперь у нас есть доступ к этому методу. Следующий:

import {connect} from 'react-redux'

Начнем с реакции-редукции. Как сказано в документации:

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

Давайте немного разберем это второе предложение. В первой части говорится, что, импортируя инструменты из библиотеки React Redux, такие как Connect, мы предоставляем нашим компонентам React доступ ко всему в хранилище Redux. Это означает глобальное состояние и действия. Чтобы привязать хранилище Redux к вашим компонентам React, вы должны:

export default connect(null, createUser)(SignupForm)

Первый аргумент в Connect имеет значение NULL. Это потому, что мы не даем этому компоненту никакого состояния из глобального хранилища. Позже мы рассмотрим пример передачи состояния компонента React из глобального хранилища. На данный момент мы должны оставить его равным нулю, поскольку connect ожидает, что там по крайней мере будет функция, которая предоставит состояние свойствам этого компонента. Если бы у нас было действие createUser без null, это было бы очень и очень запутанно.

Действия здесь - хлеб с маслом. Они предоставляют нашему приложению информацию, которая потребуется нашему редуктору для изменения состояния. Мы вызываем наше действие createUser в нашем компоненте React в этой строке кода:

this.props.createUser(this.state)

Это отправляет состояние (он же пользовательский объект, который мы только что создали с помощью этой формы) в наш файл userActions. Прежде чем мы продолжим: чтобы предоставить вашему компоненту React доступ к действию, вы должны:

  1. Импортируйте действие из соответствующего файла
  2. Импортировать Connect из React Redux
  3. Экспортируйте и подключите свою функцию или класс, как написано выше

Наше печально известное действие createUser будет выглядеть так:

// src/Actions/userActions.js //
export const createUser = (userObj) => {
   return (dispatch) => {
       fetch('http://localhost:3000/users', {
           method: 'POST',
           headers: {
               'accepts': 'application/json',
               'content-type': 'application/json'
           },
           body: JSON.stringify(userObj)
       })
       .then(response => response.json())
       .then(data => {
           dispatch({type: 'CREATE_USER', payload: data})
       })
    }
}

Да, ничего особенного… по большей части. Это похоже на обычный вызов, но что это за диспетчерская?

Redux позволяет нам иметь дело с асинхронной выборкой, предоставляя нам инструмент промежуточного слоя: Thunk. Чтобы справиться с этой асинхронной выборкой, мы должны предоставить нашим действиям отправку внутри. По сути, Thunk дает нам доступ к диспетчеризации, что дает нам доступ к асинхронности в нашем приложении. Если бы мы должны были аутентифицировать нашего пользователя, у нас также была бы отправка, указывающая на тип 'SHOW_ERROR' с полезной нагрузкой любого сообщения об ошибке в случае, что произошла ошибка с POST запрос. Пока что жизнь хороша, и нам не нужно беспокоиться об аутентификации, и нам нужна только одна отправка:

dispatch({type: 'CREATE_USER', payload: data})

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

// src/Reducers/userReducer.js //
defaultState = {currentUser: {}}
export function userReducer(state = defaultState, action){
    switch (action.type) {
       case 'CREATE_USER':
          return {
             ...state, state.currentUser: action.payload
          }
       default:
          return state;
    }
}

Здесь наше приложение видит, что тип нашего действия - «CREATE_USER», поэтому оно передает данные (наш вновь созданный пользователь из нашего вызова fetch, хранящийся в полезной нагрузке) в случай «CREATE_USER» userReducer, где наше состояние изменяется, чтобы быть равным пользователь, который только что создал учетную запись. Теперь мы можем сообщить любому из наших компонентов React об этом новом пользователе, сопоставив состояние с реквизитами. А пока передадим это в Профиль:

// src/Profile.js //
import React from 'react'
import {connect} from 'react-redux'
class Profile extends React.Component{    
   render(){
      return(
         <h1>{this.props.currentUser.username}</h1>
      )
    }  
} 
const mapStateToProps = state => { 
    return {currentUser: state.currentUser}
} 
export default connect(mapStateToProps)(Profile)

Наш профиль теперь имеет доступ к нашему currentUser и может выводить на экран в теге h1 имя пользователя currentUser. Вы заметите, что наш друг Connect снова был импортирован из React Redux. Теперь вместо того, чтобы предоставить нам доступ к определенному действию, он предоставляет нам currentUser из нашего глобального хранилища Redux. Если первый аргумент в нашем предыдущем примере для Connect был нулевым, теперь это функция mapStateToProps, которая дает нашему компоненту React Profile, опору currentUser.

Итак, следует ли мне использовать Redux? Если вы собираетесь использовать часть информации в нескольких компонентах, да. Это очистит ваш код и упростит вам доступ к информации из любого места. Однако остерегайтесь своих асинхронных действий и убедитесь, что вы всегда знаете, что происходит в вашем приложении.

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