ساخت input ها از state

15 اردیبهشت 1399
ساخت input ها از state

ساخت input ها از state

در قسمت قبل ظاهر فرم خود را تنظیم کردیم و حالا نوبت این است که فرم را واقعی تر کنیم. اگر یادتان باشد داده هایی که در فایل ContactData.js داریم و از آن برای فرم استفاده می کنیم به شکل زیر بودند:

customer: {
    name: 'Amir Zouerami',
        address: {
        street: 'Teststreet 1',
            zipCode: '9174582541',
                country: 'Iran'
    },
    email: 'test@test.com'
},
deliveryMethod: 'fastest'

اما حالا می خواهیم این اطلاعات را از خود کاربر (فرم) بگیریم  بنابراین اطلاعات بالا را از فایل ContactData.js حذف کنید و چیزی شبیه به کد زیر را درون state پیاده سازی کنید:

state = {
    orderForm: {
        name: 'Amir Zouerami',
        street: 'Teststreet 1',
        zipCode: '9174582541',
        country: 'Iran',
        email: 'test@test.com',
        deliveryMethod: 'fastest'

    },
    loading: false
}

هر کدام از این خصوصیت ها در شیء بالا یکی از input هایی هستند که باید در فرم ساخته شوند. البته باید آن را مرتب تر و البته پیشرفته تر کنیم. من می خواهم برای هر کدام از موارد بالا یک elementType داشته باشم که نوع تگ HTML را مشخص می کند (یعنی چه نوع input ای داشته باشیم، آیا textarea باشد یا input اعدی یا منوی آبشاری و...؟). سپس یک elementConfig می خواهیم تا attribute های این تگ ها را در آن مشخص کنیم. نهایتا Value را خواهیم داشت که مقدار وارد شده درون فرم است و ما باید در ابتدا آن را خالی بگذاریم. اگر من این کار را برای خصوصیت name در بالا انجام دهم با چنین کدی روبرو می شویم:

state = {
    orderForm: {
        name: {
            elementType: 'input',
            elementConfig: {
                type: 'text',
                placeholder: 'Your Name'
            },
            value: ''
        },
        street: 'Teststreet 1',
        zipCode: '9174582541',
        country: 'Iran',
        email: 'test@test.com',
        deliveryMethod: 'fastest'

    },
    loading: false
}

از آنجایی که نام یک مقدار رشته ای ساده است من از نوع input استفاده کرده ام و سپس type آن را برابر text قرار داده ام و یک placeholder نیز برای آن تعیین کرده ام. مقدار value نیز در ابتدا خالی است چرا که معلوم نیست مشتری چه کسی باشد و باید خودش اطلاعاتش را وارد کند. همچنین در نظر داشته باشید که نام خصوصیاتی مانند elementType یا elementConfig به سلیقه ی من انتخاب شده و شما می توانید آن را کاملا تغییر دهید.

حالا همین کاری را که با name کردیم با بقیه ی خصوصیات مانند street و zipcode و... نیز انجام می دهیم:

state = {
    orderForm: {
        name: {
            elementType: 'input',
            elementConfig: {
                type: 'text',
                placeholder: 'Your Name'
            },
            value: ''
        },
        street: {
            elementType: 'input',
            elementConfig: {
                type: 'text',
                placeholder: 'Street'
            },
            value: ''
        },
        zipCode: {
            elementType: 'input',
            elementConfig: {
                type: 'text',
                placeholder: 'ZIP Code'
            },
            value: ''
        },
        country: {
            elementType: 'input',
            elementConfig: {
                type: 'text',
                placeholder: 'Country'
            },
            value: ''
        },
        email: {
            elementType: 'input',
            elementConfig: {
                type: 'email',
                placeholder: 'Your E-Mail'
            },
            value: ''
        },
        deliveryMethod: {
            elementType: 'select',
            elementConfig: {
                options: [
                    { value: 'fastest', displayValue: 'Fastest' },
                    { value: 'cheapest', displayValue: 'Cheapest' }
                ]
            },
            value: ''
        }
    },
    loading: false
}

تمام موارد بالا تکراری هستند به جز خصوصیت deliveryMethod (به معنی «نحوه ی ارسال») که قرار است یک منوی آبشاری (select) باشد. من در آن دو روش ارسال سریع و اکسپرس و ارسال ارزان را قرار داده ام.

حالا که این state را بدین شکل طراحی کرده ایم باید input های خودمان را تغییر دهیم تا به صورت پویا و بر اساس state تولید شوند. در حال حاضر یک input باید ساختاری شبیه به کد زیر را داشته باشد:

<Input elementType="..." elementConfig="..." value="..." />

فعلا به جای کدها سه نقطه گذاشته ام تا فقط ساختار کلی را به شما نشان بدهم. این موارد را از همان State و فرم واقعی دریافت خواهیم کرد. در ضمن فعلا نیازی به تغییر elementType نداریم چرا که بعدا آن را به روش دیگری تغییر خواهم داد تا با خطای جلسه ی قبل روبرو نشویم. حالا به فایل Input.js می رویم و دستور switch را به شکل زیر تغیر می دهیم:

switch (props.elementType) {
    case ('input'):
        inputElement = <input className={classes.InputElement} {...props.elementConfig} />;
        break;
    case ('textarea'):
        inputElement = <textarea className={classes.InputElement} {...props.elementConfig} />
        break;
    default:
        inputElement = <input className={classes.InputElement} {...props.elementConfig} />;
}

یعنی شرط را به جای inputtype روی elementType قرار داده و در نهایت props را به صورت props.elementConfig در آورده ایم. در مرحله ی بعد باید value را نیز به آن اضافه کنیم بنابراین می گوییم:

switch (props.elementType) {
    case ('input'):
        inputElement = <input
            className={classes.InputElement}
            {...props.elementConfig}
            value={props.value} />;
        break;
    case ('textarea'):
        inputElement = <textarea
            className={classes.InputElement}
            {...props.elementConfig}
            value={props.value} />
        break;
    default:
        inputElement = <input
            className={classes.InputElement}
            {...props.elementConfig}
            value={props.value} />;
}

بعد از اضافه کردن value خط ها را شکستم تا راحت تر خوانده شوند. در مرحله ی بعد باید به ContactData.js برویم و به input های خود نگاهی بیندازیم:

let form = (
    <form>
        <Input elementType="..." elementConfig="..." value="..." />
        <Input inputtype="input" type="email" name="email" placeholder="Your Mail" />
        <Input inputtype="input" type="text" name="street" placeholder="Street" />
        <Input inputtype="input" type="text" name="postal" placeholder="Postal Code" />
        <Button btnType="Success" clicked={this.orderHandler}>ORDER</Button>
    </form>
);

چند خط بالاتر اولین input را به صورت یک ساختار کلی نوشته بودیم که در اینجا ملاحظه می شود. من می خواهم بقیه ی این input ها را نیز بر اساس این ساختار بنویسم بنابراین آن ها را حذف می کنم:

let form = (
    <form>
        <Input elementType="..." elementConfig="..." value="..." />
        <Button btnType="Success" clicked={this.orderHandler}>ORDER</Button>
    </form>
);

حالا باید state خود را به صورت یک آرایه در بیاوریم تا بتوانیم با آن کار کنیم. برای انجام این کار یک آرایه ی خالی تعریف کرده و با یک حلقه ی For خصوصیات state را در آن می گذاریم:

render() {
    const formElementsArray = [];
    for (let key in this.state.orderForm) {
        formElementsArray.push({
            id: key,
            config: this.state.orderForm[key]
        });
    }
    let form = (
        // بقیه ی کدها

اول از همه یک key برای آرایه ی خود تعریف کرده ایم تا با خطای همیشگی key برخورد نکنیم. سپس config را از شیء orderForm دریافت کرده ایم. توجه داشته باشید که [orderForm[Key برابر با مقادیر زیر است:

{
    elementType: 'input',
        elementConfig: {
        type: 'text',
            placeholder: 'Street'
    },
    value: ''
},

یعنی قسمت راست هر خصوصیت اصلی مثل name یا street یا ZipCode و غیره. حالا می توانیم درون این فرم گردش کنیم و فیلدهای فرم را به صورت پویا ایجاد کنیم:

 let form = (
    <form>
        {formElementsArray.map(formElement => (
            <Input
                key={formElement.id}
                elementType={formElement.config.elementType}
                elementConfig={formElement.config.elementConfig}
                value={formElement.config.value}
            />
        ))}
        <Button btnType="Success">ORDER</Button>
    </form>
);

مثل همیشه با تابع map در اعضای این آرایه (شیء orderForm که آن را تبدیل به آرایه ی formElementsArray کرده ایم) گردش می کنیم. برای هر عضو یک input قرار می دهیم که در واقع کامپوننت Input خودمان است نه یک input عادی HTML. فکر نمی کنم نیازی به توضیح بیشتر داشته باشیم.

حالا اگر به مرورگر برویم فرم خود را به صورت صحیح می بینیم. البته یک مشکل جزئی وجود دارد و آن هم این است که منوی آبشاری select ما به صورت صحیح نمایش داده نشده است. برای حل این مشکل وارد کامپوننت Input می شویم و یک case جدید به دستور switch اضافه می کنیم:

case ('select'):
inputElement = (
    <select
        className={classes.InputElement}
        value={props.value}>
        {props.elementConfig.options.map(option => (
            <option key={option.value} value={option.value}>
                {option.displayValue}
            </option>
        ))}
    </select>
);
break;

این case می خواهد یک منوی آبشاری برای ما بسازد. من با کد بالا این منوی select را به صورت پویا و خودکار از شیء orderForm در state فایل ContactData.js ساخته ام:

deliveryMethod: {
    elementType: 'select',
        elementConfig: {
        options: [
            { value: 'fastest', displayValue: 'Fastest' },
            { value: 'cheapest', displayValue: 'Cheapest' }
        ]
    },
    value: ''
}

در واقع در کد بالا با استفاده از تابع map بین اشیاء options گردش کردم و یک select به زبان HTML ایجاد کرده ام. ساختاری که در تابع map می بینید ساختار مورد نیاز برای ساخت یک منوی select در HTML است و ربط زیادی به جاوا اسکریپت ندارد بنابراین اگر آن را متوجه نمی شوید به نحوه ی ساخت منوهای select در HTML سری بزنید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری دوره جامع آموزش ری اکت توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما (1 دیدگاه)

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.

Reza
23 تیر 1399
سلام و خسته نباشید به شما واقعا کارتون عالی هم سایت روکسو هم نویسنده آقای زوارمی این دوره کی تکمیل میشه؟

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.