简体   繁体   中英

How Can i Add Event Handlers In Reusable React Component Created from Object Array

I am trying to create reusable components for a Dynamic address form. I need to add custom event handlers to the components. Currently each input field in the Address form is created from the following object array, Can i add custom event handlers to the following array or do I need to consider another approach to achieve these.

AddressFields.js

export const AddressFields =[
 {name:"FirstName", type:"text", title:"First Name", id:"AddressFirst" ,validate:(data)=>isNaN(data)},
 {name:"LastName", type:"text", title:"Last Name", id:"AddressLast",validate:(data)=>isNaN(data)},
 {name:"AddressLine1", type:"text", title:"Address Line 1", id:"Address1",validate:(data)=>isNaN(data)},
 {name:"AddressLine2", type:"text", title:"Address Line 2", id:"Address2",validate:(data)=>isNaN(data)},
 {name:"City", type:"text", title:"City", id:"AddressCity",validate:(data)=>isNaN(data)},
 {name:"Pin", type:"number", title:"Pin Code", id:"AddressPin",validate:(data)=>isNaN(data)},
 {name:"State", type:"text", title:"State", id:"AddressState",validate:(data)=>isNaN(data)},
 {name:"Phone", type:"number", title:"Phone ", id:"AddressPhone",validate:(data)=>isNaN(data)},
 {name:"Email", type:"email", title:"Email ", id:"AddressEmail",validate:(data)=>isNaN(data)},];

AddressForm.js

import Input from "../UI/Input"
import { AddressFields } from "./AddressFields"
const AddressForm = () => {
    return (
        <div id="ShippingAddress" className="">
            {AddressFields.map((addr)=>{
                return <Input name={addr.name} id={addr.id} title={addr.title} type={addr.type}/>
            })}
        </div>
    )
}

export default AddressForm

Input.js

import { useState } from "react";

const Input = (props) => {
    const [isValid,setIsValid]=useState(true);
    return (
        <div>
            <label for={props.name}>{props.title}</label>
            <input id={props.id} name={props.name} type={props.type} onBlur={isValid=props.validate()} />
            
        </div>
    )
}

export default Input

I think it is kind of ok to add your handler functions to the data array, especially if it is just a small project. At least it seems to be not uncommon.

But if you prefer to more strictly follow the principle of separating data and logic (as I do), then you should not add functions to data array, but only 'something' that identifies what would be valid.

Also, note that if you are using functions inside of data arrays the data array can not be stringified anymore, if that matters for you (eg for passing it around over network, workers, storage, ...).

If the requirements become more complicated , a identifier for the requirement can not be a simple key (like "isNaN" ) anymore, but you would need some kind of custom 'syntax', eg "shouldBeBetween:10,99" , which needs to be parsed.

If it gets very complicated I guess it should be considered to either stay with the functions inside the data array for the sake of simplicity (if stringify is not necessary), or to use a library that supports the desired validations.

example for separating data and logic

(for this you need to know all possible validators in advance)

export const AddressFields = [
  {
    name: "FirstName",
    ...,
    validate: [
      'isNaN',   // <-- some 'key' to identify the requirement
       ...       // <-- optionally more additional requirements
    ]
  },
];

Then you would have some collection of all possible validators, eg:

const validators = {
  isNaN: ( data ) => isNaN( data ),
  // ... more additional validators
};

For each Input you would create and call the required validators, eg:

const createValidator = function( validatorKeys ){
  return function( data ){
    return validatorKeys.every( key => {
      const currentValidator = validators.hasOwnProperty( key ) && validators[ key ];
      return currentValidator && currentValidator( data );
    })
  }
}

const Input = (props) => {
  const [ isValid, setIsValid ] = useState( true );
  const [ value, setValue ] = useState();

  const validatorForThisItem = createValidator( props.validate );

  return (
    <div>
      <label for={ props.name }>{ props.title }</label>
      <input id={ props.id } name={ props.name } type={ props.type } onBlur={ () => {
        setIsValid( validatorForThisItem( value ) );
      }} />
    </div>
  )
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM