'How to pass initial values to child components through react-hook-forms

I'm trying to pass initial values to a form (like for instance after calling an API and filling up the form). My concern is when filling values to child components (YearSelect). The code below works but I have no idea if this is the best solution using react-hook-forms.

import { useEffect } from 'react';
import { useForm } from 'react-hook-form';

function YearSelect(props) {

    useEffect(() => {
        props.setValue('year', props.data);
    });

    return (
        <select name="year" {...props.register('year')}>
            <option value="">---</option>
            <option value="2021">2021</option>
            <option value="2022">2022</option>
        </select>
    )
}

function App() {
    const { register, handleSubmit, watch, formState: { errors }, setValue, getValues } = useForm();
    let year = 0;

    useEffect(() => {
        setValue('title', 'HEY');
        setValue('year', 2021);
        year = getValues('year');
        console.log(year);
    });

    const onSubmit = data => {
        alert(1);
    }

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            Title: <input name="title" {...register('title')}/><br/>
            Year: <YearSelect name="year" register={register} data={year} setValue={setValue}/>
            <button type="submit">Save</button>
        </form>
    );
}

export default App;


Solution 1:[1]

let year = 0;

This is not a react hook based variable. When you assign value to it, the component will not track it and won't rerender itself. Instead, use

const [year, setYear] = useState(0);

//And in useEffect,
setYear(getValues('year'))

Apart from that, all other parts of the component seem to be fine.

Solution 2:[2]

I think I found another option. Using FormProvider and UseFormContext

import { useEffect, useState } from 'react';
import { useForm, FormProvider, useFormContext } from 'react-hook-form';

function YearSelect(props) {
    const { register, setValue } = useFormContext(); // retrieve all hook methods

    useEffect(() => {
        setValue('year', props.data);
    });

    return (
        <select name="year" {...register('year')}>
            <option value="">---</option>
            <option value="2021">2021</option>
            <option value="2022">2022</option>
        </select>
    )
}

function App() {
    const methods = useForm();
    const [year, setYear] = useState(0);

    useEffect(() => {
        methods.setValue('title', 'HEY');
        methods.setValue('year', 2021);
        setYear(methods.getValues('year'));
    }, []);

    const onSubmit = data => {
        alert(1);
    }

    return (
        <FormProvider {...methods}>
        <form onSubmit={methods.handleSubmit(onSubmit)}>
            Title: <input name="title" {...methods.register('title')}/><br/>
            Year: <YearSelect name="year" data={year}/>
            <button type="submit">Save</button>
        </form>
        </FormProvider>
    );
}

export default App;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 S K R
Solution 2 Ruben