简体   繁体   中英

How to share data between components in angular

I use observable to send a value from one component to another (data is sent to the subscriber after clicking on this other component, ie via subject) I subscribe in another component and everything works fine until I refresh the page, after refreshing the page the component is recreated and after recreation the subscriber has no data as he did not go through the first component.How can I solve the problem?

I tried using rxjs operators as shareReplay but it didn't work like shareReplay

This is happening because everything is in memory, and on page refresh all is lost, due the fact that angular app is re-initializing. You need to persist the state, for example write it into local storage, for this you could use "tap" operator from rxjs. And also in loading you could read data from localstorage end emit-it, for this you could use app_initializer hook.

As your Angular app is destroyed and rebuilt when the page is refreshed, unfortunately you will lose all user state that is not saved somewhere. This is a common problem in building UIs so there are a number of tools available to combat this

Strategy :

  • Store your user state when an important change is made. This is called persisting state
  • Fetch and reapply your saved state on reload. This is called hydrating state

Options :

  1. Persist to local storage and check for local storage values on reload to hydrate with
  2. Persist within the users URL (simple values only), eg modifying the URL in some way which can be checked on reload. Assuming you are dealing with a single page, query parameters or fragments may be the way to go
  3. Persist to a database via a POST/PATCH call and perform a GET request on reload to check for values to hydrate with

None of these methods are inbuilt into an RxJS operator (as far as I know) but we can easily leverage RxJS to achieve any of the above strategies with little effort. The tap operator is often used specifically to handle side effects, ie operations which should happen as a coincidence of an RxJS emission. That is precisely what we want here, in simple terms:

  • "If the subject emits a value, also trigger an operation which persists the user state"
  • "On page load, check for any available saved user state and emit via the relevant subject, hydrating the observables which the components will consume"

See example implementation below

tab.service.ts

type TabType = 'first' | 'second'

@Injectable({
  providedIn: 'root'
})
export class TabService {
  tabSelectedSubject: BehaviorSubject<TabType> = new BehaviorSubject<TabType>('first')
  tabSelected$: Observable<TabType> =
    this.tabSelectedSubject
      .pipe(
        tap(tab: TabType) => {
          // ... your persist code here
          this.saveTab()
        },
        distinctUntilChanged()
      )

  constructor() {
    // ... your hydrate code here
    this.fetchAndApplyTab();
  }

  saveTab(): void {
    localStorage.setItem('tab', tab)
  }

  fetchAndApplyTab(): void {
    const savedTab: TabType | null = localStorage.getItem('tab');
    if (savedTab) {
      this.tabSelectedSubject.next(savedTab)
    }
  }
}

In this case, we are exploiting the fact that our service is:

  • A singleton, so only loaded once per app (ie provided in the app root)
  • The service will be instantiated in the first component that loads which also injects it

This allows us to put our fetchAndApplyTab() logic in tab.service.ts 's constructor and keep the code self-contained. However, depending on your use case, you may instead want to run fetchAndApplyTab() from your component manually itself.

there are 2 days majority to pass data between components

  1. If both components are interconnected it means the parent or child relationships then you can pass data with input-output decorators.
  2. you can use the common service to share data between 2 components.

In SPA application if you refresh the browser then all in memory objects and observables are not present you need to again go back to the screen where it will be initialize.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM