Welcome to the CSC Q&A.
Get help and give help!
Write great code!
It is our choices... that show what we truly are, far more than our abilities.

Categories

+11 votes

I am working on creating two side by side components that are very similar. A majority of the code is dedicated to curating and formatting the content from the Firebase. I want to abstract these methods into 1 class that we can use for all of our Firebase calls and handling. One of the problems I see is that we have listeners that we establish, and my understanding of how listeners are a bit weak, but I think I can instantiate one and return it in the function and use it in the class that implements the method.

Does anyone have a good example of how to start an abstract class. For example I have to authenticate the firebase and would like to only have to do that once when my app mounts.

Here is some example code:

    class WatchQueue extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          matched: false,
          walker_uuid: '',
          watcher_uuid: uuid.v1()
        };
      }

  async updateWalkers() {
    var database = firebase.database().ref("users");

    console.log("Updating walkers");
    //TODO make the list a queue so that no one is left behind
    var snapshot = await database.limitToLast(1).orderByChild("havePaired").equalTo(false).on('value', (snapshot) => {
      console.log("Testing snapshot: " + snapshot);
      snapshot.forEach((childSnapshot) => {
        console.log("Parsing...");
        var childKey = childSnapshot.key;
        var childData = childSnapshot.val().havePaired;
        console.log("One result: " + childKey + " " + childData);
        //Next: set havePaired to true, and set the watcher uuid to this device's uuid
        this.updateDatabase(childSnapshot.key);
        this.setState({walker_uuid: childKey});
      })
    });
}

    updateDatabase(userId){
      console.log("Updating database...")
        firebase
          .database()
          .ref('users/' + userId)
          .update({havePaired: true,
                watcher_uuid: this.state.watcher_uuid});
        this.setState({matched: true});
    }

Now both updateDatabase() and updateWalker() should be called from a separate abstract class.

I don't believe the abstract class would extend the component, it isn't a component itself. It also might not be viewed as a Class in javacsript, I might just have to import the file as: functions so I can then call functions.doSomething() and that'll work. Has anyone else had success with this?

asked in CSC490_Spring202021 by (4.6k points)
edited by
+2

Are you using Redux for your application? The implementation will be easier if you are currently using a state management tool.

+2

We are using expo

+2

This is a react native project, so if we need a react package that might break it. I was thinking this might be a simple javascript question about abstraction.

+2

So are you using local states to store your data?

+2

I'm honestly not sure how local states work in react native.

+2

Can you please post the code for the similar components you're asking about in the question then? That'd help out with understanding the issue you're facing :)

+2

I changed the question with a bit with more code, I hope this helps, I didn't know how much would be helpful, but I can show more examples of what I am trying to abstract. Thank you!

+2

Do you have the working code prior to the refactor handy? If you haven't pushed it up, maybe a link to your GH repo would help. I have something in mind but I want to make sure I'm providing an accurate answer

+2

That is the code before refactor. You can look at the sandpiper repo under WalkQueue.js.

1 Answer

+4 votes
 
Best answer

Refactor Firebase Out

For your Firebase implementation, I'd probably separate the firebase related functions in WalkQueue to a separate file. Please take a look below:

// firebaseHelper.js - this file contains all firebase related logic
export const getWalkers = async (walker_uuid) => {
    var database = firebase.database().ref("users");

    var isMatched = false;
    var snapshot = await database.limitToLast(1)...on((..) => {
        if (childData) {
            isMatched = true;
        }
    });
    return isMatched;
}

And then in the WalkQueue component:

import { getWalkers } from './firebaseHelper.js';

class WalkQueue extends React.Component {
    constructor(props) {...}

    async componentDidMount() {
        const isMatched = await updateWalkers(this.state.walker_uuid);
        
        this.setState({ isMatched });
        console.log(this.state.walker_uuid)
    }
    
    ...rest is the same

This way, every time you want to check if there is a match, you only need to call the piece of code in the componentDidMount method. Let me know if this answer is helpful to you.

answered by (2.1k points)
selected by
+2

This helps a lot, exporting the function is new to me and then importing the function and using it is new. Thank you for providing this solution!

+2

No problem! You can also take a look at this article about High Order Component in React if you want to abstract the entire componentDidMount logic outside of the component and pass the information in as props: https://reactjs.org/docs/higher-order-components.html

...