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.

Top comments (0)