dimanche 18 août 2019

Using classes (not class components) in react to improve design architecture

I have been using React for a few months now and am diving deeper in to application structure and design patterns. Of particular interest to me is handling multiple asynchronous calls that may depend on each other, dependant on the logic of user journeys.

I am currently building an app where I have multiple asynchronous operations that include using local storage, connecting and querying Firebase for phone number authentication and also a WebRTC React Native video calling platform.

In trying to figure out how to handle data received from these apis, I have come across a few examples of code where the authors are using plain classes, not class components to help build their application. My question is, what is this design pattern called and how should I approach using it? What are the best resources to read about its use?

For example, with Firebase phone number authentication a developer I found on Github writes this:

class FirebaseService {
    user = ''
    uid = ''
    userStatusDatabaseRef = ''
    userStatusFirestoreRef = ''

    constructor() {
        firebase.auth().onAuthStateChanged((user) => {
            if (user) {
                const { uid, phoneNumber} = firebase.auth().currentUser._user
                UserStore.user.setUID(uid)
                UserStore.user.setPhoneNumber(phoneNumber)
                let ref = firebase.database().ref(`/Users/${UserStore.user.uid}`)
                ref.on('value', this.gotUserData)
            }
            this.setListenConnection()

        })
    }

    confirmPhone = async (phoneNumber) => {
        const phoneWithAreaCode = phoneNumber.replace(/^0+/,'+972'); 

        return new Promise((res, rej) => {
            firebase.auth().verifyPhoneNumber(phoneWithAreaCode)
                .on('state_changed', async (phoneAuthSnapshot) => {
                    switch (phoneAuthSnapshot.state) {
                    case firebase.auth.PhoneAuthState.AUTO_VERIFIED:
                        await this.confirmCode(phoneAuthSnapshot.verificationId, phoneAuthSnapshot.code, phoneAuthSnapshot)
                        res(phoneAuthSnapshot)

                        break

                    case firebase.auth.PhoneAuthState.CODE_SENT:
                        UserStore.setVerificationId(phoneAuthSnapshot.verificationId)
                        res(phoneAuthSnapshot)
                        break
.......

However, I just have a FirebaseService.js file, and pass in a callback to it authorizeWithToken from my container component to store a result to state via Redux in the component.

import firebase from 'react-native-firebase';

export const authorizeFirebase = (phoneNumber, authorizeWithToken) => {
  try {
    firebase.auth()
      .verifyPhoneNumber(phoneNumber)
      .on('state_changed', (phoneAuthSnapshot) => {
        // console.log(phoneAuthSnapshot);
        switch (phoneAuthSnapshot.state) {
          case firebase.auth.PhoneAuthState.CODE_SENT: // or 'sent'
            console.log('code sent');
            break;
          case firebase.auth.PhoneAuthState.ERROR: // or 'error'
            console.log('verification error');
            console.log(phoneAuthSnapshot.error);
            break;
          case firebase.auth.PhoneAuthState.AUTO_VERIFY_TIMEOUT: // or 'timeout'
            console.log('auto verify on android timed out');
            break;


          // '-------------------------------------------------------------'
          case firebase.auth.PhoneAuthState.AUTO_VERIFIED: // or 'verified'
            console.log('auto verified on android');
            const { verificationId, code } = phoneAuthSnapshot;
            const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, code);
            firebase.auth().signInWithCredential(credential).then(result => {
              const user = result.user;
              user.getIdToken().then(accessToken => {
                authorizeWithToken(accessToken);

My service is a function, and his is a class, neither of them are components.

To give another example - here is a class 'service' from a code example that is provided by video messaging platform ConnectyCube that I'm using:

import ConnectyCube from 'connectycube-reactnative'

class ChatService {
    // Chat - Core
    connect(user) {
        return new Promise((resolve, reject) => {
            if (!user) reject()

            ConnectyCube.chat.connect(
                {
                    userId: user.id,
                    password: user.password,
                },
                (error, contacts) => {
                    if (!error && contacts) {
                        resolve(contacts)
                    } else {
                        reject(error)
                    }
                },
            )
        })
    }

    disonnect() {
        ConnectyCube.chat.disconnect()
    }
}

// create instance
const Chat = new ChatService()

// lock instance
Object.freeze(Chat)

export default Chat

I haven't come across classes as services until now but I would really like to know how I should use them and what patterns I should follow. They look super useful and at the moment I have a spaghetti junction of local state, Redux and services that are connected via callbacks and complex async await setups. Any ideas greatly appreciated.

Aucun commentaire:

Enregistrer un commentaire