در قسمتهای قبلی، خیلی از ویژگیهای React را پوشش دادیم. شیوه ایجاد کنترلهای input از آبجکت configuration و اعتبارسنجی این کنترلها، تعدادی از ویژگیهایی هستند که ما در مورد آنها صحبت کرده ایم. این ویژگیها، در این قسمت از این سری آموزشی که قرار است ما درخواست PUT را به منظور آپدیت آبجکت entity خود به سمت سرور بفرستیم مفید خواهند بود.
پس بی صبرانه بریم تا کار خود را شروع کنیم.
اگر میخواهید تمام دستورالعملهای پایه و راهنمای کامل برای آموزش سریالی NET Core. را ببینید، این لینک را بررسی کنید: دستورالعملهای کار با NET Core.
این مقاله، قسمتی از مجموعه آموزشی زیر میباشد:
- آماده سازی پروژه و ایجاد component ها
- Navigation و مسیریابی (Routing)
- Axios ،HTTP و Redux
- Lazy Loading و HOC Component
- مدیریت خطا و component های اضافی
- ایجاد form داینامیک و component های modal
- اعتبارسنجی Form و Handle کردن درخواست Post
- مدیریت درخواست PUT
- مدیریت درخواست DELETE
اگر میخواهید تمام دستورالعملهای پایه و راهنمای کامل برای آموزش سریالی React را ببینید، به این لینک مراجعه کنید: مقدمه معرفی آموزش سریالی React
جهت دانلود سورس بر روی این لینک کلیک کنید: سری آموزشی React – قسمت 8
این پست به قسمتهای زیر تقسیم میشود:
- آماده سازی کامپوننت Update Owner و تنظیمات مسیریابی
- افزودن عناصر Input, اعتبارسنجی, Binding دوطرفه
- اتصال Reducer با Component
- واکشی داده ها از سرور
- نمایش داده ها بر روی صفحه
- اجرای Update Action
- نتیجه گیری
آماده سازی کامپوننت Update Owner و تنظیمات مسیریابی
داخل پوشه containers
، میتوانیم پوشه Owner را پیدا کنیم. داخل این پوشه، قصد داریم یک پوشه جدید ایجاد کرده و نام آن را UpdateOwner بگذاریم. حالا داخل این پوشه، فایل UpdateOwner.js را ایجاد میکنیم:
در این فایل، ما قصد داریم یک business logic را با reuse کردن feature هایی که قبلا در کامپوننت CreateOwner
استفاده کرده بودیم را برای آپدیت owner entity به کار ببریم. بنابراین درک این business logic نباید خیلی سخت باشد، چرا که ما تمام دانش لازم (از قسمتهای قبل) در مورد فیلدهای input، اعتبارسنجی و آبجکت state را در اختیار داریم.
پس بیایید basic logic را به فایل UpdateOwner.js اضافه کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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; |
بنابراین، ما این class component را به همراه local state خودش ایجاد کردیم. این state همان ویژگیهای کامپوننت CreateOwner را دارد: ownerForm
و isFormValid
. برای کامپوننت UpdateOwner، باید ویژگی isFormValid
را با true مقداردهی کنیم. زیرا تمام فیلدهای روی این form قرار است به محض mount شدن component پر شود. بنابراین فیلدهای ما در زمان mount شدن form همانطور که در کامپوننت CreateOwner بوده اند، نامعتبر نخواهند بود.
در compnentWillMount
lifecycle hook، ما تمام تنظیمات input را واکشی کرده و state را update میکنیم.
برای فعالسازی navigation به این component، باید فایل App.js را تغییر دهیم:
1 |
import UpdateOwner from './Owner/UpdateOwner/UpdateOwner'; |
1 |
<Route path="/updateOwner/:id" component={UpdateOwner} /> |
حالا ما میتوانیم به این کامپوننت navigate کنیم.
افزودن عناصر Input، اعتبارسنجی و Binding دوطرفه
ما قصد داریم این خط کد زیر را درست زیر تابع render
و بالای بلاک return
برای تبدیل آبجکت ownerForm
به آرایه ای از آبجکتها اضافه کنیم:
1 |
const formElementsArray = formUtilityActions.convertStateToArrayOfFormObjects({ ...this.state.ownerForm }); |
همچنین اضافه کردن import برای formUtilityActions
و کامپوننت Input
را نیز نباید فراموش کنیم:
1 2 |
import * as formUtilityActions from '../../../Utility/FormUtility'; import Input from '../../../UI/Inputs/Input'; |
سپس داخل تگ Well
، میخواهیم این کد را برای نمایش عناصر input و دکمه ها اضافه کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<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
lifecycle hook) را برای فعالسازی اعتبارسنجی و binding دوطرفه اضافه میکنیم:
1 2 3 4 5 6 7 8 |
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 }) } |
باز هم این قسمتی است که می توانیم از این کد برای اعتبارسنجی و binding دو طرفه استفاده مجدد کنیم.
در این لحظه که روی دکمه Update در کامپوننت OwnerList کلیک می کنیم، کامپوننت UpdateOwner را مشاهده می کنیم:
این خوب است، اما ما میخواهیم همه فیلدها را با دادههای صحیح owner پر کنیم.
پس اجازه دهید دقیقا همین کار را انجام دهیم.
اتصال Reducer با Component
اجازه دهید import های ضروری را در فایل UpdateOwner.js اضافه کنیم:
1 2 3 4 |
import * as repositoryActions from '../../../store/actions/repositoryActions'; import * as errorHandlerActions from '../../../store/actions/errorHandlerActions'; import { connect } from 'react-redux'; import moment from 'moment'; |
سپس میخواهیم تابع mapStateToProps
را زیر component اضافه کنیم:
1 2 3 4 5 6 7 8 |
const mapStateToProps = (state) => { return { data: state.repository.data, showSuccessModal: state.repository.showSuccessModal, showErrorModal: state.errorHandler.showErrorModal, errorMessage: state.errorHandler.errorMessage } } |
درست زیر تابع mapStateToProps
، باید تابع mapDispatchToProps
را اضافه کنیم:
1 2 3 4 5 6 7 8 |
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 را اصلاح میکنیم:
1 |
export default connect(mapStateToProps, mapDispatchToProps)(UpdateOwner); |
این هم از این.
اکنون ما ارتباط بین reducer ها و component خود را داریم و می توانیم component های modal خود را برای نشان دادن پیام های success یا error اضافه کنیم.
ابتدا، بیایید عبارات import را اضافه کنیم:
1 2 |
import SuccessModal from '../../../components/Modals/SuccessModal/SuccessModal'; import ErrorModal from '../../../components/Modals/ErrorModal/ErrorModal'; |
سپس باید component ها را زیر تگ Form
داخل تگ Well
اضافه کنیم:
1 2 3 4 5 6 7 8 |
<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()} /> |
واکشی داده ها از سرور
زیر
، ما hook دیگری را برای واکشی داده ها از سرور اضافه میکنیم:compnentWillMount
lifecycle hook
1 2 3 4 5 |
componentDidMount = () => { const id = this.props.match.params.id; const url = '/api/owner/' + id; this.props.onGetOwnerById(url, { ...this.props }); } |
در این function، ما id آن owner که میخواهیم update کنیم را میگیریم و سپس این owner را از server واکشی میکنیم. پس از آن باید local state خود را به روز کنیم (به طور دقیق تر آبجکت ownerForm در داخل آن state) تا داده های آبجکت owner را در فیلدهای input نمایش دهیم.
hook های componentWillMount
و componentDidMount
hook از نوع hook های creation lifecycle هستند. اما hook ،React های update lifecycle هم دارند که به محض ورود یک ویژگی جدید در component یا آپدیت کردن state فعال میشوند.
بنابراین، اگر به نموداری که در آن جریان Redux را توضیح دادیم نگاهی بیندازیم، می بینیم که پس از به روز رسانی state توسط reducer، قرار است central store آن state را به عنوان props در داخل کامپوننت منتشر کند. ما میتوانیم این تغییر را آن لحظه دریافت کرده و با استفاده از update lifecycle hook، آبجکت ownerForm
خود را داخل local state خود update کنیم.
نمایش داده ها بر روی صفحه
بنابراین بیایید یک update lifecycle hook جدید را زیر تابع componentDidMount
اضافه کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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
hook فقط زمانیکه یک component، یک آبجکت props جدید را دریافت میکند و نه زمانیکه ما state را update میکنیم فراخوانی میشود.
چرا این مهم است؟
خوب، برخی از update lifecycle hook ها زمانی که props جدید وارد میشود و زمانی که state را نیز بهروزرسانی میکنیم، trigger میشوند، بنابراین اگر state را در داخل آن hook بهروزرسانی کنیم و شرایط خروج را ارائه نکنیم (یک نوع عبارت if) با یک حلقه بی نهایت روبه رو میشویم. اما در مورد componentWillReceiveProps hook اینطور نیست.
در داخل componentWillReceiveProps
hook، از دستور this.props استفاده نمی کنیم، بلکه از پارامتر nextProps استفاده می کنیم زیرا حاوی شی props جدید ما است. بنابراین، تمام اقدامات در این تابع به استخراج غیرقابل تغییر ownerForm از state و قرار دادن آن در updatedOwnerform اختصاص دارد. سپس از updatedOwnerForm، میتوانیم تمام object های دیگر را نیز بهطور تغییرناپذیر استخراج کنیم (name, address و dateOfBirth). بعد از این اقدام، میتوانیم مقادیر ویژگیهای درون این آبجکتها را تغییر داده و این آبجکتها را درون updatedOwnerForm برگردانیم. در آخر میتوانیم state را با آبجکت جدید updatedOwnerForm به روزرسانی کنیم.
حالا وقتی به form خود می رویم این form ظاهر متفاوتی پیدا می کند:
اجرای Update Action
در پایان، اجازه دهید تا دو function را برای redirect شدن به کامپوننت OwnerList در صورت کلیک بر روی دکمه Cancel و به روز رسانی entity در صورت کلیک بر روی دکمه update اضافه کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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}); } |
خب این هم از این. اکنون می توانیم عملکرد به روز رسانی را آزمایش کنیم.
ما میتوانیم کد روی سرور Web API را برای آزمایش کامپوننتهای modal خود جهت واکنش به response های موفقیت آمیز و خطا، تغییر دهیم. علاوه بر این، میتوانیم اعتبارسنجی form را با خالی کردن فیلدهای ورودی یا تایپ بیش از 60 کاراکتر در قسمت ورودی آدرس آزمایش کنیم.
نتیجه گیری
با خواندن این پست، شما یاد گرفتید که:
- چطور از hook های lifecycle مختلف برای واکشی داده ها از سرور و آپدیت یک local state استفاده کنید
- نحوه handle کردن درخواست PUT در پروژه خود
بابت خواندن این مقاله از شما تشکر میکنیم و امیدواریم که برای شما مفید واقع قرار گرفته باشد.
در قسمت بعدی این سری از آموزش، که ما آموزش React را به پایان میرسانیم، قصد داریم نحوه handle کردن درخواست Delete در application را یاد بگیریم.