GithubHelp home page GithubHelp logo

Comments (2)

AndreaPallotta avatar AndreaPallotta commented on May 1, 2024 1

I think the issue is that there is no "reactive" relation between ICounterRepository.instance.count and the context. The value is only retrieved once because it is a getter. One way to fix it is to introduce a useState and a useEffect in between with a context provider, where the state "subscribes" and is updated based on the ICounterRepository.instance.count.

I cloned your project and added the following code to make it work:

ICounterRepository.ts:

// Added a new interface
export interface CounterObserver {
    update(): void;
}

...

// Added these three observer methods to the abstract class
abstract addObserver(observer: CounterObserver): void;
abstract removeObserver(observer: CounterObserver): void;
abstract notifyObservers(): void;

CounterRepository.ts:

// Added a new variable to the class
private observers: CounterObserver[] = [];

...

increment(): void {
    this._count++;
    console.log(`Count is now ${this._count}`)
    this.notifyObservers(); // Added this line to trigger the state update which will be reflected in the UI
}

// Defined the three abstract observer methods in the class
addObserver(observer: CounterObserver): void {
    this.observers.push(observer);
}

removeObserver(observer: CounterObserver): void {
    const index = this.observers.indexOf(observer);
    if (index !== 1) this.observers.splice(index, 1);
}

notifyObservers(): void {
    this.observers.forEach((observer: CounterObserver) => {
        observer.update();
    })
}

CounterRepositoryProvider.tsx (a new file in src/data/counter/):

import { ReactNode, useEffect, useState } from 'react';
import { HomePageViewModel, HomePageViewModelType } from '../../view/home_page/HomePageViewModel';
import { CounterObserver, ICounterRepository } from './ICounterRepository';

export const HomePageViewModelProvider = ({ children }: { children: ReactNode }) => {
 
    // this state is what will allow the UI to be retriggered on change
    const [count, setCount] = useState<number>(ICounterRepository.instance.count);

    useEffect(() => {
        /* 
         We define the observer to link the class and the UI in a reactive way.
         When the count variable is updated in the class, the observers are notified and the state variable
         is updated (setCount), triggering the UI to update
        */
        const observer: CounterObserver = {
            update: () => {
                setCount(ICounterRepository.instance.count);
            }
        }
        
        // "subscribe" the observer to the class instance
        ICounterRepository.instance.addObserver(observer);
        
       // clear the observer when it's not needed anymore (i.e. on dismount)
        return () => {
            ICounterRepository.instance.removeObserver(observer);
        }
    }, []);

    const increment = () => {
        ICounterRepository.instance.increment();
    }

    const viewModel: HomePageViewModelType = {
        count, increment
    }

    // I personally like defining the Provider here to avoid having to import additional objects to the view file
    return (
        <HomePageViewModel.Provider value={viewModel}>
            {children}
        </HomePageViewModel.Provider>
    )
}

App.tsx:

export default function App() {
  return (
    <HomePageViewModelProvider> // Import and wrap the code with the Provider
      <View style={styles.container}>
        <Text>Open up App.tsx to start working on your app!</Text>
        <HomePage/> // NOTE: you can just wrap the HomePage if nothing else uses the context
        <StatusBar style="auto" />
      </View>
    </ HomePageViewModelProvider>
  );
}

Capture

Apologies for the long code. There are definitely better ways to do this. However, I tried to make it work with modify the least amount of code so that it's not too confusing. I hope it helps

from react.

juskek avatar juskek commented on May 1, 2024 1

BEAUTIFUL :)

This behaviour is exactly what I was looking for; will let you know if I find a way to implement this with less boilerplate, but thank you very much!

from react.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.