Подготовка компонента UpdateOwner и настройка маршрутизации
Внутри папки containers
мы можем найти папку Owner
. Внутри этой папки мы создадим новую и назовем ее UpdateOwner
. Давайте создадим внутри новый файл UpdateOwner.js
:
В этом файле мы собираемся обработать бизнес-логику для обновления объекта-владельца, повторно используя функции, которые мы уже использовали в компоненте CreateOwner
. Следовательно, эту бизнес-логику не должно быть слишком сложно понять, потому что у нас уже есть все необходимые знания из предыдущих частей о полях ввода, проверке и объекте состояния.
Добавим базовую логику нашего компонента в файл UpdateOwner.js
:
import React, { Component } from 'react';
import { Form, Well, Button, FormGroup, Col } from 'react-bootstrap';
import { returnInputConfiguration } from '../../../Utility/InputConfiguration';
class UpdateOwner extends Component {
state = {
ownerForm: {},
isFormValid: true
}
componentWillMount = () => {
this.setState({ ownerForm: returnInputConfiguration() });
}
render() {
return (
<Well>
</Well>
)
}
}
export default UpdateOwner;
Итак, мы создали компонент класса с его локальным состоянием. Это состояние имеет те же свойства, что и компонент CreateOwner: ownerForm
и isFormValid
. Для компонента UpdateOwner нам нужно установить для свойства isFormValid
значение true, потому что все поля в форме будут заполнены, как только компонент будет смонтирован. Следовательно, наши поля не будут недействительными при монтировании формы, как это было в компоненте CreateOwner
.
В хуке жизненного цикла compnentWillMount
мы получаем всю входную конфигурацию и обновляем состояние.
Чтобы включить переход к этому компоненту, нам нужно изменить файл App.js
:
import UpdateOwner from './Owner/UpdateOwner/UpdateOwner';
<Route path="/updateOwner/:id" component={UpdateOwner} />
Теперь мы можем перейти к этому компоненту.
Добавление элементов ввода, проверка и двусторонняя привязка
Сразу под функцией render
и над блоком return
мы собираемся добавить эту строку кода для преобразования объекта ownerForm
в массив объектов:
const formElementsArray = formUtilityActions.convertStateToArrayOfFormObjects({ ...this.state.ownerForm });
Не забудьте добавить оператор импорта для компонентов formUtilityActions
и Input
:
import * as formUtilityActions from '../../../Utility/FormUtility';
import Input from '../../../UI/Inputs/Input';
Затем внутри тега Well
мы добавим этот код для отображения элементов ввода и кнопок:
<Form horizontal onSubmit={this.updateOwner}>
{
formElementsArray.map(element => {
return <Input key={element.id} elementType={element.config.element}
id={element.id} label={element.config.label}
type={element.config.type} value={element.config.value}
changed={(event) => this.handleChangeEvent(event, element.id)}
errorMessage={element.config.errorMessage} invalid={!element.config.valid}
shouldValidate={element.config.validation}
touched={element.config.touched}
blur={(event) => this.handleChangeEvent(event, element.id)} />
})
}
<br />
<FormGroup>
<Col mdOffset={6} md={1}>
<Button type='submit' bsStyle='info' disabled={!this.state.isFormValid}>Update</Button>
</Col>
<Col md={1}>
<Button bsStyle='danger' onClick={this.redirectToOwnerList}>Cancel</Button>
</Col>
</FormGroup>
</Form>
Это код, который мы использовали в одном из предыдущих постов. Давайте добавим функцию handleChangeEvent
(под хуком жизненного цикла componentWillMount
), чтобы включить проверку и двустороннюю привязку:
handleChangeEvent = (event, id) => {
const updatedOwnerForm = { ...this.state.ownerForm };
updatedOwnerForm[id] = formUtilityActions.executeValidationAndReturnFormElement(event, updatedOwnerForm, id);
const counter = formUtilityActions.countInvalidElements(updatedOwnerForm);
this.setState({ ownerForm: updatedOwnerForm, isFormValid: counter === 0 })
}
Опять же, это раздел, в котором мы можем повторно использовать код для проверки и двусторонней привязки.
В этот момент, когда мы нажимаем кнопку "Обновить" в компоненте OwnerList
, мы увидим представление UpdateOwner:
Это нормально, но мы хотим заполнить все поля правильными данными владельца.
Итак, давайте сделаем именно это.
Соединение редьюсера с компонентом
Давайте добавим необходимые операторы импорта в файл UpdateOwner.js
:
import * as repositoryActions from '../../../store/actions/repositoryActions';
import * as errorHandlerActions from '../../../store/actions/errorHandlerActions';
import { connect } from 'react-redux';
import moment from 'moment';
Затем мы собираемся добавить функцию mapStateToProps
под компонентом:
const mapStateToProps = (state) => {
return {
data: state.repository.data,
showSuccessModal: state.repository.showSuccessModal,
showErrorModal: state.errorHandler.showErrorModal,
errorMessage: state.errorHandler.errorMessage
}
}
Чуть ниже функции mapStateToProps
нам нужно добавить функцию mapDispatchToProps
:
const mapDispatchToProps = (dispatch) => {
return {
onGetOwnerById: (url, props) => dispatch(repositoryActions.getData(url, props)),
onUpdateOwner: (url, owner, props) => dispatch(repositoryActions.putData(url, owner, props)),
onCloseSuccessModal: (url, props) => dispatch(repositoryActions.closeSuccessModal(props, url)),
onCloseErrorModal: () => dispatch(errorHandlerActions.closeErrorModal())
}
}
Наконец, давайте изменим оператор экспорта:
export default connect(mapStateToProps, mapDispatchToProps)(UpdateOwner);
Теперь у нас есть связь между редьюсерами и нашим компонентом, и мы можем добавить наши модальные компоненты для отображения сообщений об успехе или ошибках.
Сначала добавим операторы импорта:
import SuccessModal from '../../../components/Modals/SuccessModal/SuccessModal';
import ErrorModal from '../../../components/Modals/ErrorModal/ErrorModal';
Затем нам нужно добавить компоненты под тегом Form
, но внутри тега Well
:
<SuccessModal show={this.props.showSuccessModal} modalHeaderText={'Success message'}
modalBodyText={'Action completed successfully'}
okButtonText={'OK'}
successClick={() => this.props.onCloseSuccessModal('/owner-List', { ...this.props })} />
<ErrorModal show={this.props.showErrorModal} modalHeaderText={'Error message'}
modalBodyText={this.props.errorMessage}
okButtonText={'OK'}
closeModal={() => this.props.onCloseErrorModal()} />
Получение данных с сервера
Ниже хука жизненного цикла compnentWillMount
мы собираемся добавить еще один крючок для получения данных с сервера:
componentDidMount = () => {
const id = this.props.match.params.id;
const url = '/api/owner/' + id;
this.props.onGetOwnerById(url, { ...this.props });
}
В этой функции мы берем идентификатор владельца, которого хотим обновить, а затем получаем этого владельца с сервера. После этого нам нужно обновить наше локальное состояние (точнее, объект ownerForm внутри этого состояния), чтобы отображать данные от объекта-владельца в полях ввода.
Перехватчики componentWillMount
и componentDidMount
являются перехватчиками жизненного цикла создания. Но в React есть перехватчики жизненного цикла update, которые срабатывают, как только новое свойство поступает в компонент или мы обновляем состояние.
Итак, если мы посмотрим на диаграмму, на которой мы объясняли поток Redux, мы можем видеть, что после того, как редуктор обновит состояние, центральное хранилище будет распространять это состояние как props
внутри компонента. Мы можем поймать это изменение в этот момент и обновить наш объект ownerForm
внутри нашего локального состояния с помощью хука жизненного цикла обновления.
Отображение данных на экране
Поэтому давайте добавим новый хук жизненного цикла обновления под функцией componentDidMount
:
componentWillReceiveProps = (nextProps) => {
const updatedOwnerForm = { ...this.state.ownerForm };
let nameObject = { ...updatedOwnerForm.name };
let dateObject = { ...updatedOwnerForm.dateOfBirth };
let addressObject = { ...updatedOwnerForm.address };
nameObject.value = nextProps.data.name;
nameObject.valid = true;
dateObject.value = moment(nextProps.data.dateOfBirth);
addressObject.value = nextProps.data.address;
addressObject.valid = true;
updatedOwnerForm['name'] = nameObject;
updatedOwnerForm['dateOfBirth'] = dateObject;
updatedOwnerForm['address'] = addressObject;
this.setState({ ownerForm: updatedOwnerForm });
}
Хук componentWillReceiveProps
вызывается только тогда, когда компонент получает новый объект props , но не, когда мы обновляем состояние.
Что ж, некоторые из хуков жизненного цикла обновления будут срабатывать, когда прибывают новые реквизиты, а также когда мы обновляем состояние, поэтому, если мы обновим состояние внутри этого хука и не предоставим условие выхода (какой-то тип if оператор), мы получим бесконечный цикл. Но это не относится к хуку componentWillReceiveProps
.
Внутри хука componentWillReceiveProps
мы используем не оператор this.props
, а параметр nextProps
, поскольку он содержит наш новый объект props
. Таким образом, все действия в этой функции предназначены для неизменного извлечения ownerForm из состояния и помещения его в updatedOwnerform
. Затем из updatedOwnerForm
мы можем неизменно извлекать все другие объекты (имя, адрес и дату рождения). После этого действия мы можем изменить значения свойств внутри этих объектов и вернуть эти объекты внутри updatedOwnerForm
. Наконец, мы можем обновить состояние с помощью нового объекта updatedOwnerForm
.
Теперь наша форма при переходе к ней выглядит иначе:
Выполнение действия обновления
В конце давайте добавим две функции для перенаправления на компонент OwnerList, если мы нажмем кнопку "Отмена", и для обновления объекта:
redirectToOwnerList = () => {
this.props.history.push('/owner-List');
}
updateOwner = (event) => {
event.preventDefault();
const ownerToUpdate = {
name: this.state.ownerForm.name.value,
dateOfBirth: this.state.ownerForm.dateOfBirth.value,
address: this.state.ownerForm.address.value
}
const url = "/api/owner/" + this.props.data.id;
this.props.onUpdateOwner(url, ownerToUpdate, {...this.props});
}
Теперь мы можем протестировать функциональность обновления.
Мы можем изменить код на сервере веб-API, чтобы он отвечал успешно, и сообщения об ошибках, чтобы проверить наши модальные компоненты. Кроме того, мы можем протестировать проверку формы, опустив поля ввода или введя более 60 символов в поле ввода адреса.
Заключение
Прочитав этот пост, вы узнали:
- Как использовать разные хуки жизненного цикла для получения данных с сервера и обновления локального состояния.
- Как обрабатывать PUT-запросы в нашем проекте
Спасибо, что прочитали статью, и я надеюсь, что вы нашли в ней что-то полезное.
В следующей части серии, где мы завершаем наше путешествие по серии React, вы узнаете, как обрабатывать запросы на удаление в нашем приложении.