How to manage CRUD operations for nested data with react-query to a flask-restx api

23 Views Asked by At

I have been working on a project where the user is able to create multiple-choice quizzes. I have the database models which define Quiz, Question, and Option:

Option = { 
  id: number;
  text: string; 
  point_value: number; 
  question_id: number;
}

Question = {
  id: number;
  text: string;
  options: Option[]
  quiz_id: number;
}

Quiz = {
  id: number;
  title: string;
  questions: Question[]
}

In my app I have tried two methods of fetching and mutating this data:

  1. Creating API routes for each model, where posting to that route with a matching JSON Schema will compare that to the current state of that database model and commit any changes.
  2. Creating API routes for getting and updating each individual attribute.

Both of these methods feel wrong, as they require a lot of (sometimes redundant) API calls constantly and have made it incredibly hard to allow for optimistic updates.

Here is a basic Quiz Editor component in its current state. It is only responsible for rendering a list of QuestionCard, where each QuestionCard has QueryInput components that link editable attributes of each question (text, option.text, and option.point_value) to the database:

// Editor.tsx
function Editor() {
  const { quiz } = useQuizContext();
  
  return (
    {quiz.questions.map((question) => (
      <div>
        <QuestionCard question={question}/> 
      </div>
    ))}
  )
  
}

// QueryInput.tsx
type QueryInputProps = {
  id: number
  fetchFunction: (id: number) => Promise<any>
  updateFunction: (id: number, value: string) => Promise<any>
}

function QueryInput({ id, fetchFunction, updateFunction }: QueryInputProps) {
  const queryClient = useQueryClient()
  const query = useSuspenseQuery({
    queryKey: [fetchFunction.name, id]
    queryFn: () => fetchFunction(id)
  })

  const mutation = useMutation({
    mutationFn: (newValue: string) => updateFunction(id, newValue)
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: [fetchFunction.name, id]
      })
    }
  })

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    newValue = e.target.value
    mutation.mutate(newValue)

  }

  return (
    <input 
      defaultValue={query.data}
      onChange={handleChange}
    />
  )

}

My gut tells me to take advantage of Immer and the QueryCache to handle all (nested) data modification, but I don't understand how to reflect these changes to my API.

If anyone can offer help with this solution or suggest an alternative, I would be very grateful. Thanks!

0

There are 0 best solutions below