revilos
revilos

Reputation: 13

Where should I put my logic for writing new data to Firestore?

I'm currently working on a project with React and Firebase and at the moment my logic to write new data to Firestore is directly in my components. I'm now also integrating Redux, for this I am using react-redux-firebase. My question is now, where is the best place to put this logic, because it makes my component quiet bloated.

In the documentation of react-redux-firebase, they've also put it directly in the component, but their logic is quit simple, mine is a little bit more complex, like this handleSubmit:

const handleSubmit = async (e) => {
    e.preventDefault();
    setDisabled(true); //disable button to prevent multiple sbumits
    setLoading(true);

    try {
      const docRef = await firestore.collection("goodies").add(newGoodieData); // create new event
      await firestore.collection("goodies").doc(docRef.id).update({
        // add eventId to event doc
        id: docRef.id,
      });

      if (image) {
        const imageName = docRef.id + "." + image.name.split(".").pop(); //create image name with eventID and file extions

        const imageRef = storage.ref().child("goodie_images/").child(imageName); //create imageRef

        const imageSnapshot = await imageRef.put(image); //upload image to storage

        const downloadUrl = await imageSnapshot.ref.getDownloadURL(); //get image download-url

        const imagePath = imageRef.fullPath; // get image storage path

        await firestore.collection("goodies").doc(docRef.id).update({
          //update event with imageUrl and imagePath
          image: downloadUrl,
          imagePath: imagePath,
        });
      }
      setDisabled(false);
      setLoading(false);

      dispatch(showSuccessToast(`Created new goodie "${newGoodieData.name}"!`));
      history.push("/goodies");
    } catch (error) {
      dispatch(showErrorToast("Ops, an error occurred!"));
      console.error(error.message);
    }
  };

Upvotes: 1

Views: 142

Answers (1)

LeadDreamer
LeadDreamer

Reputation: 3499

This is entirely my idiosyncrasy, but I use a structure like the below. In general, component and page (i.e react component) names are initial-capital:

src
|-blocks
|-components
|-css
|-navigation
|-pages
|-services
|-App.js
|-constants.js
|-index.js

BLOCKS

These are my application-specific components, and some larger application-specific functions.

|-blocks
  |-Block1
  | |-index.js
  | |-aSubModule.js
  |-Block2
  | |-index.js
  | |-aSubModule.js
etc, etc

COMPONENTS

These are "generalized" components - i.e could be released as modules, or are customized from external modules. These are NOT application-specific. Similar structure to "blocks"

|-components
  |-ComponentThatDoesThisThing
  |-ComponentThatDoesThatThing
etc, etc

CSS

As the name says...

NAVIGATION

Headers, Footers, navigation menus. Also navigation helper functions (such as wrapping links to pages, etc)

|-navigation
  |-Header
  |-Menu
  |-Footer
etc, etc

PAGES

All my react pages and sub-pages, to whatever depth are needed. Everything below pages is specific to the application

|-pages
  |-Users
  | |-Home
  | | |index.js
  | | |-etc,etc
  | |-Account
  | |-Bio
  | |-etc,etc
  |-Owners
  | |-Home
  | |-Account
  | |-Bio
  | |-etc,etc
  |-index.js  

And where your question is more directly addressed:

SERVICES

|-services
  |-reduxEnhancers
  |-reduxMiddleware
  |-reduxRootReducers
  |-slices
  |-configureStore.js
  |-firestore.js

Not yet much different than the tutorials. But this is what I have in my slices - which more-or-less-ish correspond to redux state slices:

SLICES

|-services
  |-slices
    |-UserSlice
    | |-actions
    | | |-index.js
    | |-reducer
    | | |-index.js
    | |-business
    | | |-index.js
    | |-index.js
    |-OwnerSlice
    | |-actions
    | | |-index.js
    | |-reducer
    | | |-index.js
    | |-business
    | | |-index.js
    | |-index.js
    |-KitchCupboardSlice
    | |-actions
    | | |-index.js
    | |-reducer
    | | |-index.js
    | |-business
    | | |-index.js
    | |-index.js
    |-etc,etc slices
    |-index.js

IMPORTANT NOTE: most Redux tutorials show the Redux slices having the same branching structure as the React components. In general THIS IS NOT AT ALL THE CASE, and I have yet to find a case where it is even helpful. The tree-like structure of your data is not necessarily at all like the tree-like structure of your pages and react components - divide your Redux store the way the data wants you to, not the way the user-facing React wants you to. Even more to the point for this forum: let the FIRESTORE structure of your data guide you.

In use:

|-services
  |-slices
    |-UserSlice
    |-index.js

...for example, imports and then exports all the public/exported symbols from actions, reducer and business.

|-services
  |-slices
    |-UserSlice
     |-reducer

...reducer uses store.injectReducer to add itself to the Redux store, using symbols and constants defined in

|-services
  |-slices
    |-UserSlice
     |-actions

...actions, which also creates the specific Redux actions and helper boiler plate (actions, selectors, etc).

To help separate responsibility:

|-services
  |-slices
    |-UserSlice
     |-business

...business sub-directory holds the BUSINESS logic you mentioned - any logic that a React component might need to call that is NOT specifically local to the display & state aspects of the React modules. This is ALSO where I define any access to firestore, or any other external service or fetches - the React components should NOT care how this is done.

To make accessing all of these various exports more convenient, I use

|-services
  |-slices
    |-index

...which imports and then exports all the public/exported symbols from all the slices. Makes it easier to import into various React comopnents without worrying about changes to the underlying structure of slices

As I said, COMPLETELY my idiosyncrasy, but it helps to separate out responsibility.

Upvotes: 1

Related Questions