DEV Community

Kailana Kahawaii
Kailana Kahawaii

Posted on

Creating a Dynamically Controlled Form in React: Additional Parts

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.

Oldest comments (0)