skip to Main Content

I get this error in my console when trying to submit a form in my react/redux app using rtk query with firebase/firestore.

Cannot read properties of undefined (reading ‘error’)

I think the issue is with my handle submit function. When I click on the save button, the data get saved in my firestore database; but because it throws an error, it doesn’t execute uptill the line where the entered data has to be cleared from the form and fetched back to the page. Until I reload the browser, then the entered data is cleared, the error disappears and the data is fetched and rendered. This is a bad user experience and I think I’m missing something in the handleSubmit function.

Any hint on how I can resolve this?

Below is the codebase where I’m using the handleSubmit function

import React, { useState, useEffect } from 'react';
import { storage } from '../../services/firebase';
import { ref, uploadBytesResumable, getDownloadURL } from 'firebase/storage';
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { useAddPostsMutation } from '../../services/postsApi';

const initialState = {
  title: '',
  content: '',
};

const AddEditPosts = () => {
  const [data, setData] = useState(initialState);
  const [file, setFile] = useState(null);
  const [progress, setProgress] = useState(null);
  const [addPosts] = useAddPostsMutation();

  const { title, content } = data;

  useEffect(() => {
    const uploadFile = () => {
      const storageRef = ref(storage, file.name);
      const uploadTask = uploadBytesResumable(storageRef, file);

      uploadTask.on(
        'state_changed',
        (snapshot) => {
          const progress =
            (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
          console.log('Upload is ' + progress + '% done');
          setProgress(progress);
          switch (snapshot.state) {
            case 'paused':
              console.log('upload is paused');
              break;
            case 'running':
              console.log('upload is running');
              break;
            default:
              break;
          }
        },
        (error) => {
          console.log(error);
        },
        () => {
          getDownloadURL(uploadTask.snapshot.ref)
            .then((downloadURL) => {
              toast.info('Imagee uploaded successfully');
              setData((prev) => ({ ...prev, imgURL: downloadURL }));
            })
            .catch((error) => {
              // Handle error gracefully
              console.error('Error getting download URL: ', error);
              toast.error('Error Uploading image');
            });
        }
      );
    };
    file && uploadFile();
  }, [file]);

  const handleChange = (e) => {
    setData({ ...data, [e.target.name]: e.target.value });
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (title && content) {
      const result = await addPosts(data);
      console.log('result', result);

      if (result && result.error) {
        console.error('Error add post:', result.error);
        // Handle error appropriately (e.g. show a toast, display an error message)
      }
    } else {
      // Clear the form or perform any other necessary actions upon successful submission
      setData(initialState);
      setFile(null);
    }
  };
  return (
    <section>
      <h2>Add a New Post</h2>
      <form onSubmit={handleSubmit}>
        <label htmlFor='postTitle'>Post Title:</label>
        <input
          type='text'
          id='title'
          name='title'
          value={title}
          onChange={handleChange}
        />
        <label htmlFor='postContent'>Content:</label>
        <textarea
          id='content'
          name='content'
          value={content}
          onChange={handleChange}
        />
        <div>
          <input type='file' onChange={(e) => setFile(e.target.files[0])} />
        </div>
        <button type='submit' disabled={progress !== null && progress < 100}>
          Save Post
        </button>
      </form>
    </section>
  );
};

export default AddEditPosts;

2

Answers


  1. Chosen as BEST ANSWER

    I was misled by my browser console to think that the source of the error was from my handleSubmit function to add post. Howvever, the error was from my addPost endpoint in my createAPI function. The addPost endpoint saves data to the firestore database and returns nothing. However, the fakeBaseQuery() works in such a way that it returns either data value or error. And when there was no data to return since it was a post operation, it returned error. Below is my updated code for clarification

    // other code here
    export const postsApi = createApi({
      reducerPath: 'postsApi',
      baseQuery: fakeBaseQuery(),
      tagTypes: ['Post'],
      endpoints: (builder) => ({
        addPosts: builder.mutation({
          async queryFn(data) {
            try {
              await addDoc(collection(db, 'posts'), {
                ...data,
                timestamp: serverTimestamp(),
              });
              return { data: 'ok' }; // Adding this line of code solve my issue
            } catch (err) {
              return { error: err };
            }
          },
          invalidatesTags: ['Post'],
        }),
    })
    

    I got the solution from watching a youtube video on rtkquery with firebase/firestore. You can check the the redux documentation on rtk query for better understanding.


  2. As I see handleSubmit function checks if result exists, so it is impossible such an error be thrown there. console.error is also can’t throw such an error, so my suggestion: the problem here: toast.error('Error Uploading image');

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search