Lifting the state from child to parent with React 18

63 Views Asked by At

I want to capture the data in my UserInput component and bring it back to the App.jsx and store it in the state.

My investment object looks like

const [initialInvestment, setInitialInvestment] = useState({
        initialInvestment: 100,
        annualInvestment: 200,
        expectedReturn: 3.3,
        duration: 4
    });

The object looks like

{
    initialInvestment: 100,
    annualInvestment: 200,
    expectedReturn: 3.3,
    duration: 4
}

My JSX code for the component UserInput.jsx

    <div id={'user-input'}>
        <div className={'input-group'}>
            <div>
                <label>Initial Investment</label>
                <input type={'number'} defaultValue={investment.initialInvestment} onKeyDown={event => onInvestmentUpdate(event)} required/>
            </div>
            <div>
                <label>Annual Investment</label>
                <input type={'number'} defaultValue={investment.annualInvestment} onKeyDown={event => onInvestmentUpdate(event)} required/>
            </div>
            <div>
                <label>Expected Return</label>
                <input type={'number'} defaultValue={investment.expectedReturn} onKeyDown={event => onInvestmentUpdate(event)} required/>
            </div>
            <div>
                <label>Duration</label>
                <input type={'number'} defaultValue={investment.duration} onKeyDown={event => onInvestmentUpdate(event)} required/>
            </div>
        </div>
    </div>

I need to lift the state from the UserInput and bring it to App.jsx

App.jsx

const investmentHandler = (investment) => {
    //const newInvestment = [...initialInvestment, ...investment];
    setInitialInvestment(prevInvestment => {
        return {
            ...prevInvestment,
            investment
        }
    });
}

        <UserInput init={initialInvestment} onUpdate={investmentHandler}/>
2

There are 2 best solutions below

0
GettingStarted On BEST ANSWER

UserInput.jsx

    <section id={'user-input'}>
        <div className={'input-group'}>
            <p>
                <label>Initial Investment</label>
                <input type={'number'} name={'initialInvestment'} value={investment.initialInvestment} onChange={event => onUpdate('initialInvestment', event.target.value)} required/>
            </p>
            <p>
                <label>Annual Investment</label>
                <input type={'number'} name={'annualInvestment'} value={investment.annualInvestment} onChange={event => onUpdate('annualInvestment', event.target.value)} required/>
            </p>
            <p>
                <label>Expected Return</label>
                <input type={'number'} name={'expectedReturn'} value={investment.expectedReturn} onChange={event => onUpdate('expectedReturn', event.target.value)} step={'0.1'} required/>
            </p>
            <p>
                <label>Duration</label>
                <input type={'number'} name={'duration'} value={investment.duration} onChange={event => onUpdate('duration', event.target.value)} required/>
            </p>
        </div>
    </section>

App.jsx

const handleChange = (inputIdentifier, newValue) => {
    setUserInput(previousUserInput => {
        return {
            ...previousUserInput,
            [inputIdentifier]: newValue
        };
    });
}

<UserInput investment={userInput} onUpdate={handleChange}/>
2
isherwood On

Here are fundamental data down/events up principles applied to your app as I understand it. I haven't worked through all the details, but it gives you an idea how it should look.

One thing I'm not clear on is why you only have an event handler for one input, yet you seem to want to update the entire object in the app's handler. I'd update object properties individually from specific form values, or just wait for the entire form to be submitted and do it all then.

// App.jsx
const App = () => {

    const [initialInvestment, setInitialInvestment] = useState({
        initialInvestment: 100,
        annualInvestment: 200,
        expectedReturn: 3.3,
        duration: 4
    });

    const onInvestmentChange = investment => {
        setInitialInvestment(prevInvestment => {
            return {
                ...prevInvestment,
                investment
            }
        });
    }

    return (
        <UserInput investment={initialInvestment} onUpdate={onInvestmentChange}/>
    );
}

// UserInput.jsx
const UserInput = props => {
    const onInitialInvestmentChange = event => {
        const newData = [... props.investment];

        newData.initialInvestment = event.currentTarget.value;

        props.onUpdate(newData);
    }
    
    // other similar functions for each input
    const onAnnualInvestmentChange = event => {}
    const onExpectedReturnChange = event => {}
    const onDurationChange = event => {}

    return (
        <div id={'user-input'}>
            <div className={'input-group'}>
                <div>
                    <label>Initial Investment</label>
                    <input type={'number'} value={investment.initialInvestment}
                           onKeyDown={event => onInitialInvestmentChange(event)}
                           required/>
                </div>
                <div>
                    <label>Annual Investment</label>
                    <input type={'number'} value={investment.annualInvestment}
                            onKeyDown={event => onAnnualInvestmentChange (event)}/>
                </div>
                <div>
                    <label>Expected Return</label>
                    <input type={'number'} value={investment.expectedReturn}
                            onKeyDown={event => onExpectedReturnChange (event)}/>
                </div>
                <div>
                    <label>Duration</label>
                    <input type={'number'} value={investment.duration}
                            onKeyDown={event => onDurationChange (event)}/>
                </div>
            </div>
        </div>
    );
}