Setting initial values of a form via an API call
Asked Answered
G

3

8

In my React game, I use a React library called Formik for a form.

In it, you set the initial values for the form like this:

<Formik
    initialValues={{
        characterClasses: ["1", "3", "9"],
        race: "Elf",
        name: "Derolt",
        age: "84",
        
        ..etc
        

But now, I'm in a situtation where I want to load the initial values from an API call.

So I created this:

const fetchGameCharData = async (gameId) => {
    const game = await axios("api/games/" + gameId);
    // return the result
    return game;
};

My problem is, I can't figure out how to use the above fetch method to actually populate the initialValues part that Formik uses.

Has anyone ever done this?

Thanks!

Gorgon answered 17/7, 2020 at 18:9 Comment(0)
T
7

Use conditional-rendering approach.

Load your form only after you get the response from API call. Show loading... or a custom spinner until you get API response.

With this approach, your form directly load with initial values without any flickering of having no values at first load and values comes up in a flash as a result of API response.

Edit

// In your state add two values like
initialValues: [],
isValueLoded: false

...

// Make your API call in `componentDidMount`
componentDidMount() {
    // Call your API
    fetchGameCharData(....).then(res => {
        this.setState({ isValueLoded: true, initialValues: res.values});
    }).catch(err => ....);
}

....

// In your render method
render() {

    return !this.state.isValueLoded ?
       (<div>Loading...</div>) : (
        <Formki
          values={this.state.initialValues}
         ....
         />
    );
}
Tenpin answered 17/7, 2020 at 18:43 Comment(3)
I'm not sure I understand. So I have my API call...how does that run and automatically load into InitialValues? Thanks!Gorgon
Updated sample code for you. You can improvise based on your requirement. @yash answer helps you in case you are using function component. Approach is same as above.Tenpin
Pass enableReinitialize prop to Formik also.Bagworm
C
3

If you are using class component:

componentDidMount() {
    this.fetchGame();
}

async fetchGame() {
    const game = await fetchGameCharData(GAME_ID);
    this.setState({ game });
}
...
// in render method
const { game } = this.state;
...
<Formik
    initialValues={game}
...

If you are using functional component:

const { game, setGame } = useState();

useEffect(async () => {
    const game = await fetchGameCharData(GAME_ID);
    setGame(game);
}, []);

...
// in return
<Formik
    initialValues={{
        characterClasses: ["1", "3", "9"],
        race: "Elf",
        name: "Derolt",
        age: "84",
        ...
    }}
    values={game}
...

Just make sure to render the Formik only when the game is available. Otherwise it will be error as initialValues require an object has all properties needed for the form.

Chapen answered 17/7, 2020 at 18:42 Comment(10)
Thanks but this is a functional component that uses React hooks...Gorgon
that case is added as wellChapen
One thing that I don't get is that the Formik documentation sets value on individual items...like... name: "Fred", age: "30", PlayerClass: "Wizard".....etcGorgon
each property is presenting a form control?Chapen
actually i am not very sure what you mean about the above comment, but you could add the link to the documentation hereChapen
well each property value is assigned to the appropriate form controlGorgon
Thanks...this page has a very simple example: formik.org/docs/api/formikGorgon
i think values will be better than initialValues for your case.Chapen
so ... values={game} ?Gorgon
initialValues is a required field, so you may predefine it with all form controls. and values will update your form as the api response arrives. I updated the functional component in my answer.Chapen
G
1

This is an example for your problem :

const [officeInfo, setOfficeInfo] = useState({})  
async function fetchOfficeInfo() {
    try {
      const response = await iaxios.get(url)
      setOfficeInfo(response.data)
    
    } catch (error) {
      console.log(error)
    }
  }
 useEffect(() => {
    fetchOfficeInfo()
  }, [])
  ....
  
  <Formik
  enableReinitialize={true}
  initialValues={officeInfo}
  ...
  />
Gernhard answered 5/6, 2023 at 8:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.