user3869304
user3869304

Reputation: 873

How to create a reusable input field using react?

I have InputField component which accepts various props like type,placeholder,value, etc. i am trying to create a form using InputField component. I can easily pass props from form but i cant save input values to my state. Here is my code.

InputField.js

import React, { useState } from "react";

const InputField = ({ value, label, placeholder, type, onChange }) => {
  const handleChange = (e) => {
    const { value } = e.target;
    onChange(value);
  };

  return (
    <div className="form-group">
      {label && <label htmlFor="input-field">{label}</label>}
      <input
        type={type}
        value={value}
        className="form-control"
        placeholder={placeholder}
        onChange={handleChange}
      />
    </div>
  );
};

export default InputField;

AddProductForm.js

import React, { useState } from "react";
import { Form, Button } from "reactstrap";
import InputField from "../UI/InputField";

const AddProductForm = () => {
  const [inputValue, setInputValue] = useState({ name: "", price: "" });
  const { name, price } = inputValue;

  const handleChange = (inputValue) => {
    setInputValue({ name: inputValue, price: inputValue });
    console.log(inputValue);
  };
  return (
    <Form>
      <InputField
        type="text"
        value={name}
        placeholder="Product Name"
        label="Name"
        onChange={handleChange}
      />
      <InputField
        type="number"
        value={price}
        placeholder="Add Price"
        label="Price"
        onChange={handleChange}
      />
      <Button color="primary">Add</Button>{" "}
      <Button color="secondary">Cancel</Button>
    </Form>
  );
};

export default AddProductForm;

Upvotes: 9

Views: 32123

Answers (3)

Sumit Wadhwa
Sumit Wadhwa

Reputation: 3217

Here's how to do it with TypeScript:

import { InputHTMLAttributes, forwardRef, ComponentProps } from "react";
import cn from "classnames";

type TInput = InputHTMLAttributes<HTMLInputElement> & {
  label?: string;
  wrapperClasses?: ComponentProps<"div">["className"];
};

export const Input = forwardRef<HTMLInputElement, TInput>(
  ({ wrapperClasses, label, className, id, name, value, ...rest }, ref) => {
    return (
      <div className={wrapperClasses}>
        {label && (
          <label htmlFor={id} className="pl-1 mb-1 inline-block font-semibold">
            {label}
          </label>
        )}
        <input
          ref={ref}
          id={id}
          name={name}
          value={value}
          className={cn(
            "border-2 border-primary bg-red transition h-12 px-5 rounded-md focus:outline-none w-full text-black text-lg",
            className
          )}
          {...rest}
        />
      </div>
    );
  }
);

Then we'd just use it like this:

 <Input
      ref={inputRef}
      label="Username"
      type="text"
      placeholder="Enter your username"
      wrapperClasses="mb-5"
      value={username}
      onChange={(e) => setUsername(e.target.value)}
      classname="py-5" // <-- override default input css defined in Input component
  />

Upvotes: 0

Mulugeta Adamu
Mulugeta Adamu

Reputation: 19

tools react hooks,[mantine/core components]
[1]: https://mantine.dev/ yup schema and react hooks form for form validations styled components shared-input-text-filed.tsx

import { TextInput as customTextInput } from '@mantine/core'; 
import styled from 'styled-components';
type TextInputProps = {
  key: string;
  disabled?: boolean;
  variant?: 'primary' | 'danger' | 'warning';
  size?: 'sm' | 'lg';
  className?: string;
  icon?: any;
  register: any;
  required?: boolean;
  error?: string;

};

    const StyledTextInput = styled(customTextInput)``;
    
    export const SharedTextFiled= (props: TextInputProps) => {
      return (
        <StyledTextInput
          variant={props.variant}
          type="text"
          classNames={{
            icon: 'border-r w-16 text-black h-full flex  ',
            withIcon: 'items-center',
            input: 'indent-0',
          }}
          className={props.className}
          disabled={props.disabled}
          key={props.key}
          required={props.required}
          error={props.error}
          icon={props.icon ? <>{props.icon}</> : ''}
          {...props.register}
        ></StyledTextInput>
      );
    };

component-form.tsx

import { SharedTextInput} from '../../../shared/components/shared-text-input-filed';
<SharedTextInput
                        register={{ ...register('name') }}
                        className="mb-2"
                        icon={lang}
                        required={true}
                        error={errors?.name?.name?.message}
                      />

Upvotes: 2

xom9ikk
xom9ikk

Reputation: 2289

Try passing from InputField event instead of value. Then in the handler you can take the input name and understand which field should be updated.

Of course, by first adding name field for input as shown below:

InputField.js

import React  from "react";

const InputField = ({ value, label, name, placeholder, type, onChange }) => (
  <div className="form-group">
    {label && <label htmlFor="input-field">{label}</label>}
    <input
      type={type}
      value={value}
      name={name}
      className="form-control"
      placeholder={placeholder}
      onChange={onChange}
    />
  </div>
);

export default InputField;

AddProductForm.js

import React, { useState } from "react";
import InputField from "../UI/InputField";

const AddProductForm = () => {
  const [inputValue, setInputValue] = useState({ name: "", price: "" });
  const { name, price } = inputValue;

  const handleChange = (e) => {
    const { name, value } = e.target;
    setInputValue((prev) => ({
      ...prev,
      [name]: value,
    }));
    console.log(inputValue);
  };

  return (
     <Form>
       <InputField
         type="text"
         value={name}
         placeholder="Product Name"
         label="Name"
         name="name"
         onChange={handleChange}
       />
       <InputField
         type="number"
         value={price}
         placeholder="Add Price"
         label="Price"
         name="price"
         onChange={handleChange}
       />
       <Button color="primary">Add</Button>{" "}
       <Button color="secondary">Cancel</Button>
     </Form>
  );
};

export default AddProductForm;

Upvotes: 28

Related Questions