I'm trying tok create a simple demo CRUD app using React and Graphql
I have the backend all set and working.
On the front end I'm using React with useQuery and useMutation.
I have the create working with useMutation to create the data and the read with useQuery to show the data.
I now stuck with the delete. I have a button the post and I can get the id of the post to pass to the useMutation function to delete the post.
I'm just stuck getting it to work if anyon can help.
App.tsx
import React, { useState } from 'react';
import './App.css';
import { RecipeData } from '../generated/RecipeData';
import { GET_ALL_RECIPES, ADD_RECIPE, DELETE_RECIPE } from '../queries';
import { useQuery, useMutation } from 'react-apollo-hooks';
const App: React.FC = () => {
const [name, setName] = useState<string>('')
const [description, setDes] = useState<string>('')
const [id, setId] = useState<string>('')
const handleNameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setName(e.target.value)
}
const handleDesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDes(e.target.value)
}
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
createRecipe()
};
const handelDelete = (e: React.MouseEvent<HTMLButtonElement>) => {
setId(e.target.parentElement.getAttribute("data-id"))
deleteRecipe()
}
const [deleteRecipe] = useMutation(DELETE_RECIPE, {
variables: { id }, refetchQueries: ['RecipeData']
})
const [createRecipe, { error }] = useMutation(ADD_RECIPE, {
variables: { name, description }, refetchQueries: ['RecipeData']
})
if (error) {
console.error('erroring : ', error)
}
const { data, loading } = useQuery<RecipeData | null>(GET_ALL_RECIPES, {
suspend: false
})
if (loading || !data) return <div>Loading</div>
return (
<div className="App">
<h1>Graphql</h1>
<ul>
{
data.recipe !== null && data.recipe.map((recipe, i) => (
<li key={recipe._id} data-id={recipe._id}>
{recipe.name}
<button onClick={handelDelete}>X</button>
</li>
))
}
</ul>
<form>
<div>
<label>Name</label>
<input
type="text"
value={name}
onChange={handleNameChange}
/>
</div>
<div>
<label>Description</label>
<input
type="text"
value={description}
onChange={handleDesChange}
/>
</div>
<button onClick={handleClick}>Add Recipe</button>
</form>
</div>
);
}
export default App;
queries/index.tsx
import { gql } from 'apollo-boost';
export const GET_ALL_RECIPES = gql`
query RecipeData{
recipe{
_id
name
description
}
}
`
export const ADD_RECIPE = gql`
mutation addRecipe($name: String!, $description:String){
addRecipe(name: $name, description: $description){
_id
name
description
}
}
`
export const DELETE_RECIPE = gql`
mutation deleteRecipe($id: Int!){
deleteRecipe(_id: $id){
_id
name
description
}
}
`
Server side
schema.js
exports.typeDefs = `
type Recipe{
_id: ID
name: String
description: String
}
type Query{
recipe:[Recipe]
}
type Mutation{
addRecipe(name: String!, description: String):Recipe
deleteRecipe(_id: Int):Recipe
}
`
resolvers.js
exports.resolvers = {
Query:{
recipe: async(obj, args, {Recipe}, info) => {
const allRecipes = await Recipe.find()
return allRecipes
}
},
Mutation:{
addRecipe: async(obj, {name, description}, {Recipe}, info) => {
const newRecipe = await new Recipe({
name,
description
}).save()
return newRecipe
},
deleteRecipe: async(obj, args, {Recipe}, info, {_id}) => {
delete Recipe[_id];
}
}
}
I don't have a live demo sorry but this outputs a list of recipe name with an input field to add new recipes, this part works.
I also have a delete button after each recipe displayed. I wanted to click this button and have that recipe be removed from the list.
At the moment when I click this delete button I get the following error message in the network tab of the dev tools
message: "Variable "$id" got invalid value ""; Expected type Int. Int cannot represent non-integer value: """
const [id, setId] = useState<string>('')
eventually ends up atmutation deleteRecipe($id: Int!){...
– Andy Mardell