1

I want to create an Input component to be used to compose new form elements.

const Input = ({ value, children }) => {

    const [currentValue, setCurrentValue] = useState();

    return <div className='input'>
        {children}
    </div>
};

And my Text component would be:

const Text = (props) => {
    return <Input {...props}>
        <input 
            type='text'
            value={/*how to bind to currentValue of Input*/}
            onChange={/*how to call Input's setCurrentValue here*/}
        />
    </Input>
}

I need to store currentValue state in parent, because I need to manage it for many different inputs.

Also I'm stuck at how to call parent's setCurrentValue on child's onChange method.

Any help is appreciated.

Update: CodeSandbox

Update 2: Real code from my repository

Hossein Fallah
  • 1,859
  • 2
  • 18
  • 44
  • `onChange={(e) => setCurrentValue(e.target.value)}`. I suggest that instead of directly calling `setCurrentValue`, you create a function in the parent component that calls the `setCurrentValue`. You can bind that function to `onChange` event as: `onChange={handleInputChange}` – Yousaf Aug 17 '21 at 04:49
  • How? Can you please show me? Because in your solution I get `handleInputChange is not defined`. – Hossein Fallah Aug 17 '21 at 05:08
  • Did you define `handleInputChange` function first? Can you create codesandbox demo and share the link? – Yousaf Aug 17 '21 at 05:09
  • [Demo](https://codesandbox.io/s/small-rain-5057f?file=/src/App.js) – Yousaf Aug 17 '21 at 05:33
  • @Yousaf, I had no idea that the `children` can be called as a function. – Hossein Fallah Aug 17 '21 at 05:45
  • only if you pass a function. – Yousaf Aug 17 '21 at 05:46
  • @Yousaf, I tried to use that solution, but I got stuck at `muiName`. I provided a demo of that. Can you help me with that? – Hossein Fallah Aug 17 '21 at 06:30

2 Answers2

1

Please try like this.

// pass props to children.

const Input = ({ value, children }) => {

const [currentValue, setCurrentValue] = useState();

return <div className='input'>
        {React.cloneElement(child, {onChange: setCurrentValue, value: currentValue}))}
    </div>
};

// using props in childern.

const Text = (props) => {
return <Input {...props}>
        {
            ({onChange, value})=> (
                <input 
                   type='text'
                   value={value}
                   onChange={(e)=>onChange(e.target.value)}
                />
            )
        }
    </Input>
}
F.E
  • 688
  • 6
  • 10
1

Solutions:

  • Context API
  • Pass props to children
  • Use children as funciton & pass relevant

Send that reference somehow using any method you see fit.

My preference: Composition with function


const Input = ({ value, children }) => {

    const [currentValue, setCurrentValue] = useState();

    const handlChange = (e) => {
       setCurrentValue(e.target.value);
    };

    return <div className='input'>
        {children(handlChange)}
    </div>
};

const Text = (props) => {
    return <Input {...props}>
        { (handleChange) => (
           <input 
            type='text'
            onChange = ( handleChange }
           />
        ) }
    </Input>
}

Explanations:

tanmoy
  • 1,276
  • 1
  • 10
  • 28