skip to Main Content

I have a parent component which maps through my array and prints out various iterations of my Child components.

I’m trying to access the state in the parent component but can’t figure out how to lift the correct state of "inputValue" from the child and have it in the parent instead.

Ideally I’d like the inputValue and isValidated state living in the PARENT so I can use it for various form-based functions.

Parent Component:

import React, { useState } from 'react';
import { formFieldsData } from './FormFields';
import Input from './Input';

export default function Form() {

    return (
        <form>
            {formFieldsData.map((item) => (
                <Input
                    key={item.id}
                    id={item.id}
                    label={item.label}
                    type={item.type}
                    placeholder={item.placeholder}
                />
            ))}
        </form>
    )
}

Child component:

import React, { useState } from 'react';
import styles from './forms.module.scss';
import RangeInput from './RangeInput';

export default function Input({ type, id, placeholder = '', label, props }) {
    const [inputValue, setInputValue] = useState('');
    const [isValidated, setIsValidated] = useState(false);
    const isRangeInput = type === 'range';

    const handleChange = (e) => {
        setInputValue(e.target.value)
        if(inputValue.length >  0 || type === 'date') {
            setIsValidated(true)
        }
    }

    return (
        <div className={styles.form__row}>
            <label htmlFor={id}>{label}: {inputValue}</label>
            {isRangeInput
                ? <RangeInput id={id} onChange={(e) => handleChange(e)} />
                : <input
                    required
                    type={type}
                    id={id}
                    name={id}
                    placeholder={placeholder}
                    className={styles.input}
                    value={inputValue}
                    onChange={(e) => handleChange(e)}
                />
            }
            <button type="submit" id="formSubmit" onClick={() => alert('button click catched')} disabled={!isValidated}>Submit!</button>
        </div>
    )
}

2

Answers


  1. The easiest way for this is to manage your state in the parent. Then you just need to pass a function to your child as a prop to update the parent’ state. Here is one of my previous answer related to this problem and demonstrating how to apss data from child to parent.

    Note that you should do this kind of prop drilling only when it’s a direct child. If your tree expand between parent and child then a context/state management would be more apropriate.

    Login or Signup to reply.
  2. a) Just add the following function in your parent component.

    const inputDataHandler = (inputData) => {
        console.log(inputData);
    }
    

    b) Now, pass the inputDataHandler function using props to your child component.

    <Input
      key={item.id}
      id={item.id}
      label={item.label}
      type={item.type}
      placeholder={item.placeholder}
      inputDataHandler = {inputDataHandler}
    />
    

    c) Now, just call the inputDataHandler function with the arguments from child component by the handleChange function. Arguments can be value/state etc. Here, I have passed "inputValue" as argument.

    const handleChange = (e) => {
        setInputValue(e.target.value)
        if(inputValue.length >  0 || type === 'date') {
            setIsValidated(true)
        }
        props.inputDataHandler(inputValue);
    }
    

    The concept is, you write & pass the function as props to the child, when child calls that function with arguments, those arguments are passed to parent component. In this way, a value can be passed from child to parent. This concept is called "Lifting state up".

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search