Creating a Dynamically Controlled Form in React: Additional Parts
Tags: react, javascript
Published: 2020-09-18 21:04:49


In my previous articles, I talked about how to build a dynamically controlled form on the frontend and how to save that data to the backend. In this last installment, I’ll go over the final piece to make this form possible: the API call and additional parts needed.

## Posting a recipe

For simplicity’s sake, the API call to post a recipe is stored at the App level. 

The constructor holds information for our user as well as our recipes. 


```
constructor() {
    super();
    this.state = {
      auth: {
        user: {},
        recipes: [], 
      }
    };
  }
```

Data from the form is stored in a newRecipe object. For additional security, the user_id could be changed to something else, such as their access token. 


```
let newRecipe = {
   title: newRecipeState.title,
   summary: newRecipeState.summary,
   ingredients: newRecipeState.ingredients,
   steps: newRecipeState.steps,
   tags: newRecipeState.tags,
   user_id: this.state.auth.user.id
 }
 
```

Then, that data is sent to the backend. I use a console.log to verify the data I’m working with when in the testing phase, but this should be taken out for the final product. 


```
 return fetch("http://localhost:3000/api/v1/recipes", {
   method: "POST",
   headers: {
     "Content-Type": "application/json",
     Accept: "application/json",
     Authorization: localStorage.getItem("token")
   },
   body: JSON.stringify(newRecipe)
 })
 .then(resp => resp.json())
 .then(data =>
   console.log(data))
 }
```

I’ve used the browser router library to display the different components and pass down props and functions in the render method. 

```
<Route
           exact
           path='/add-recipe'
           render={props => <AddRecipeForm {...props} onAddRecipe={this.addRecipe}/>}
         />
```

## Editing a recipe 


The editing API call follows similar logic. The recipe’s id is needed to update its information.

```
 editRecipe = (recipe_id, editRecipeState) => {
  
   let editedRecipe = {
     title: editRecipeState.title,
     summary: editRecipeState.summary,
     ingredients: editRecipeState.ingredients,
     steps: editRecipeState.steps,
     tags: editRecipeState.tags,
     user_id: this.state.auth.user.id
   
  
   }
   return fetch(`http://localhost:3000/api/v1/recipes/${recipe_id}`,{
     method: "PATCH",
     headers: {
       "Content-Type": "application/json",
     Accept: "application/json",
     Authorization: localStorage.getItem("token")
     },
     body: JSON.stringify(editedRecipe)
    }).then(resp => resp.json())
       .then(data =>
         (data))
 }
```
In addition, the edit route also relies on the id path. 

```
   <Route
           path='/recipes/edit/:id'
           render={props => <EditForm {...props} appState={this.state} onEditRecipe = {this.editRecipe}/>}
           />
```


Now that we can post and edit a recipe, we ought to be able to view it as well. Although I originally wrote this series to specifically talk about form creation, it’s important to consider how all the pieces work together to create a functional site. 

The good news is that viewing the recipes is the most straightforward part of the site. Write a fetch function to populate the state with recipes. 

```
fetchRecipes = () =>{
    api.recipes.getRecipes().then(data => {
      this.setState({
        recipes: data
      })
    })
  }
```

Tie the fetch to componentDidMouth lifecycle method. 

```
componentDidMount(){
   this.fetchRecipes()
}
```

In addition, write the logic to render a list of recipes and a single recipe. 

```
 <Route
             exact
             path='/recipes'
             render={props => <RecipeList {...props} appState={this.state}/>}
           />
 
           <Route
           exact
           path='/recipes/:id'
           render={props => <RecipeDetail {...props} appState={this.state}/>}
           />
```


## Food for thought 

I made this before learning about Redux and other state management tools. Hooks, for instance, could also make the codebase much cleaner and manageable. If you’re implementing a pure React app that uses classes, the previous functions provide a good starting point. However, the overall logic for creating a dynamically controlled form should remain the same no matter which tools you use.