Welcome to the CSC Q&A, on our server named in honor of Ada Lovelace. Write great code! Get help and give help!
It is our choices... that show what we truly are, far more than our abilities.

Categories

+12 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 (1 point)
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 (1 point)
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

...