简体   繁体   English

angular中组件之间如何共享数据

[英]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?我使用 observable 将值从一个组件发送到另一个组件(数据在单击另一个组件后发送给订阅者,即通过主题)我订阅另一个组件并且一切正常,直到我刷新页面,刷新页面后组件被重新创建,重新创建后订阅者没有数据,因为他没有通过第一个组件 go。我该如何解决这个问题?

I tried using rxjs operators as shareReplay but it didn't work like shareReplay我尝试使用 rxjs 运算符作为 shareReplay 但它不像 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.发生这种情况是因为一切都在 memory 中,并且由于 angular 应用程序正在重新初始化,页面刷新时所有内容都丢失了。 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.您需要保留 state,例如将其写入本地存储,为此您可以使用 rxjs 中的“tap”运算符。并且在加载时您可以从 localstorage end emit-it 读取数据,为此您可以使用 app_initializer 挂钩。

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.由于您的 Angular 应用程序在刷新页面时被销毁并重建,不幸的是您将丢失所有未保存在某处的用户 state。 This is a common problem in building UIs so there are a number of tools available to combat this这是构建 UI 时的常见问题,因此有许多工具可以解决这个问题

Strategy :策略

  • Store your user state when an important change is made.进行重要更改时存储您的用户 state。 This is called persisting state这叫做持久化 state
  • Fetch and reapply your saved state on reload.在重新加载时获取并重新应用您保存的 state。 This is called hydrating state这个叫补水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.坚持用户 URL(仅限简单值),例如以某种方式修改 URL,可以在重新加载时检查。 Assuming you are dealing with a single page, query parameters or fragments may be the way to go假设您正在处理单个页面, 查询参数或片段可能是 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通过POST/PATCH调用持久化到数据库,并在重新加载时执行 GET 请求以检查要补充的值

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.这些方法都没有内置到 RxJS 运算符中(据我所知),但我们可以轻松地利用 RxJS 来轻松实现上述任何策略。 The tap operator is often used specifically to handle side effects, ie operations which should happen as a coincidence of an RxJS emission. tap运算符通常专门用于处理副作用,即应该作为 RxJS 发射的巧合发生的操作。 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" “在页面加载时,检查任何可用的已保存用户 state 并通过相关主题发出,从而补充组件将消耗的可观察值”

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)一个 singleton,所以每个应用程序只加载一次(即在应用程序根目录中提供)
  • 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.这允许我们将我们的fetchAndApplyTab()逻辑放在tab.service.ts的构造函数中并保持代码独立。 However, depending on your use case, you may instead want to run fetchAndApplyTab() from your component manually itself.但是,根据您的用例,您可能希望自己从组件手动运行fetchAndApplyTab()

there are 2 days majority to pass data between components大多数情况下有 2 天时间在组件之间传递数据

  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.您可以使用公共服务在 2 个组件之间共享数据。

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.在 SPA 应用程序中,如果您刷新浏览器,那么 memory 中的所有对象和可观察对象都不存在,您需要再次 go 返回到它将被初始化的屏幕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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