@equinor/fusion-framework-react-app

中文文档
14.3.9发布于 2026/11/12ISCTypeScriptES Module近 30 天下载 8095
中文使用文档
文档目录27 节
  1. 特征
  2. 安装
  3. 使用量
  4. 启动应用程序
  5. 访问模块
  6. HTTP 请求
  7. MSAL 认证
  8. A. 背景情况
  9. 导航/路由
  10. 州管理层
  11. 安装
  12. 设置
  13. 基本用途
  14. 跨组件同步
  15. 高级使用
  16. 最佳做法
  17. 特性旗
  18. 地物标志
  19. 作用
  20. 书签
  21. 设置
  22. 环境变量
  23. 测试
  24. API 参考
  25. 核心出口(主要切入点)
  26. 分路径入口
  27. 配置

@ equinor/ 组合框架- 反应- app

用于构建模块化Fusion框架应用程序的回放绑定. 为访问框架模块(HTTP, 认证, 上下文, 导航, 书签, 角色, 设置等) 提供渲染辅助工具 , 配置回调, 和 React hooks .

特征

  • 单行程序拖带 通过 renderApp —— 创建渲染函数,将组件上载为 React 18's createRoot
  • 模块钩 —— 说 useAppModule 编号 : useAppModules 用于安全进入任何已注册模块
  • 分路径入口 用于可选能力: MSAL 认证、 HTTP、 上下文、 导航、 书签、 角色、 特征旗帜、 设置、 分析、 AG 网格主题、 帮助中心、 和装入程序
  • 环境变量 钩- useAppEnvironmentVariables 用于运行时访问 app 配置
  • 懒惰装入 ——组件被包入 React.lazy + 键 Suspense 自动

安装

pnpm add @equinor/fusion-framework-react-app

使用量

启动应用程序

// config.ts
import type { AppModuleInitiator } from '@equinor/fusion-framework-react-app';

export const configure: AppModuleInitiator = (configurator) => {
  configurator.configureHttpClient('my-api', {
    baseUri: 'https://api.example.com',
    defaultScopes: ['api://my-api/.default'],
  });
};

// App.tsx
export const App = () => <h1>Hello Fusion</h1>;

// index.ts
import { renderApp } from '@equinor/fusion-framework-react-app';
import { App } from './App';
import { configure } from './config';

export const render = renderApp(App, configure);
export default render;

访问模块

import { useAppModule } from '@equinor/fusion-framework-react-app';

const MyComponent = () => {
  const auth = useAppModule('auth');
  // ...
};

HTTP 请求

import { useHttpClient } from '@equinor/fusion-framework-react-app/http';

const MyComponent = () => {
  const client = useHttpClient('my-api');
  // client.fetch$('endpoint').subscribe(...)
  // await client.fetchAsync('endpoint')
};

MSAL 认证

说明: 要求数 @equinor/fusion-framework-module-msal. MSAL 模块必须由主机/端口配置——应用程序只应消耗钩.

import { useCurrentAccount, useAccessToken } from '@equinor/fusion-framework-react-app/msal';

const UserInfo = () => {
  const user = useCurrentAccount();
  const { token } = useAccessToken({ scopes: ['User.Read'] });
  if (!user) return <p>Not signed in</p>;
  return <p>Welcome, {user.name}</p>;
};

A. 背景情况

import { useCurrentContext } from '@equinor/fusion-framework-react-app/context';

const ContextInfo = () => {
  const context = useCurrentContext();
  return <p>Selected: {context?.title ?? 'none'}</p>;
};

导航/路由

import { useRouter } from '@equinor/fusion-framework-react-app/navigation';
import { RouterProvider } from '@equinor/fusion-framework-react-router';

const routes = [{ path: '/', element: <Home /> }];

const App = () => {
  const router = useRouter(routes);
  return <RouterProvider router={router} />;
};

州管理层

Fusion框架提供了强大的状态管理解决方案,能够以自动同步的方式持续地,跨组件状态共享. 与传统的React状态在页面刷新中丢失不同,这种状态在应用会话间持续并保持在不同组件间实时同步.

主要惠益:

  • 🔄 持久性状态:幸存页面刷新并重新启动应用程序
  • 🔗 交叉组件同步: 任何组件之间立即共享状态
  • ⚡ 优化更新: 自动回滚错误的响应UI
  • 🛡️ 类型安全: 全类型脚本支持和类型推论
  • 🎯 简单 API: 工作类 useState 但坚持不懈

使用大小写 :

  • 用户偏好和设置
  • 表格数据应持续
  • 类似过滤、排序或视图模式的 UI 状态
  • 需要在多个组成部分之间共享的数据
  • 昂贵业务的缓存管理

安装

首先,安装状态模块包:

pnpm install @equinor/fusion-framework-module-state

设置

启用应用程序配置中的状态模块 。 初始化持续存储并制作 useAppState 您可在您的申请中找到:

import { enableAppState } from '@equinor/fusion-framework-react-app/state';
export const configure: ModuleInitiator = (appConfigurator) => {
  enableAppState(appConfigurator);
};

[叹息] 状态管理模块是一个强大的工具,但是在您的应用中使用它时必须了解潜在的陷阱和局限性. 国家管理是全球性的,如果不仔细使用,可能导致出乎意料的行为.

实例1: 如果有多个依赖于同一状态的组件,更新一个组件中的状态会导致所有使用该状态的组件的重接,可能导致性能问题.

实例2: 用户打开了应用程序的多分页,每个分页都在修改相同的状态. 这会导致出乎意料的行为,因为一个标签中所做的修改会被反映到所有标签中. (类似于存储选定列的用户首选项)

基本用途

使用 useAppState 就像反应一样 useState自动坚持 第一个参数是一个独特的密钥,第二个参数是一个带有默认值的选项对象:

import { useAppState } from '@equinor/fusion-framework-react-app/state';

const Counter = () => {
  const [count, setCount] = useAppState('counter', { defaultValue: 0 });
  return (
    <div>
      <span>Count: {count}</span>
      <button onClick={() => setCount((prev) => (prev ?? 0) + 1)}>Increment</button>
    </div>
  );
};

跨组件同步

多个组件可以通过使用相同的密钥来共享相同的状态. 一个组件的更改自动更新所有其他组件 :

import { useAppState } from '@equinor/fusion-framework-react-app/state';

const Incrementer = () => {
  const [count, setCount] = useAppState('counter', { defaultValue: 0 });
  return (
    <button onClick={() => setCount((prev) => (prev || 0) + 1)}>
      Increment
    </button>
  );
};

const Display = () => {
  const [count] = useAppState('counter', { defaultValue: 0 });
  return <span>Current count: {count}</span>;
};

// Usage in your app
const App = () => (
  <div>
    <Incrementer />
    <Display />
  </div>
);

高级使用

有类型脚本的复杂对象 :

interface UserPreferences {
  theme: 'light' | 'dark';
  language: string;
  notifications: boolean;
}

const SettingsPanel = () => {
  const [settings, setSettings] = useAppState<UserPreferences>('user-settings', {
    defaultValue: { theme: 'light', language: 'en', notifications: true }
  });

  const toggleTheme = () => {
    setSettings(prev => ({
      ...prev!,
      theme: prev!.theme === 'light' ? 'dark' : 'light'
    }));
  };

  return <button onClick={toggleTheme}>Theme: {settings?.theme}</button>;
};

清除状态 :

// Remove from storage completely
const clearSettings = () => setSettings(undefined);

最佳做法

避免断层关闭

[尖叫声] 在基于当前值更新状态时,始终使用更新器功能来防止同时更新中出现 stale 关闭问题.

const [count, setCount] = useAppState('counter', { defaultValue: 0 });

// ❌ Bad: Can use stale value in rapid updates
const increment = () => setCount(count + 1);

// ✅ Good: Always gets the latest value
const increment = () => setCount(prev => (prev || 0) + 1);

状态密钥组织

为更好的组织使用分级命名 :

// ✅ Good - hierarchical, descriptive
'user.profile.personal'
'user.preferences.theme'
'app.settings.notifications'
'feature.dashboard.filters'

// ❌ Avoid - flat, unclear
'userdata'
'settings'
'stuff'

使用强打字

// ✅ Good - strong typing
interface UserProfile {
  id: string;
  name: string;
  email: string;
}

const [user, setUser] = useAppState<UserProfile>('user.profile');

// ❌ Avoid - weak typing
const [user, setUser] = useAppState('user.profile');

[! TIP] 验证复合型Schemas 使用库像 zod 或者说 yup 在使用复杂状态计划之前验证它们.

const userSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(2).max(100),
  email: z.string().email(),
});

type UserProfile = z.infer<typeof userSchema>;

// ✅ Good - strong typing with validation
const useMyUser = () => {
  const [value, setValue] = useAppState<UserProfile>('user.profile');
  const setUser = useCallback((user: UserProfile) => {
    if (userSchema.safeParse(user).success) {
      setValue(user);
      return true;
    } else {
      console.warn('Provided user is invalid');
      return false;
    }
  }, [setValue]);
  if(!userSchema.safeParse(value).success) {
    console.warn('Current user state is invalid');
    return null;
  }
  return value;
};

特性旗

地物标志

说明: 要求数 @equinor/fusion-framework-module-feature-flag。 。 。 .

import { enableFeatureFlag } from '@equinor/fusion-framework-react-app/feature-flag';

export const configure: AppModuleInitiator = (configurator) => {
  enableFeatureFlag(configurator, [
    { key: 'dark-mode', title: 'Dark mode' },
    { key: 'beta-ui', title: 'Beta UI', allowUrl: true },
  ]);
};
import { useFeature } from '@equinor/fusion-framework-react-app/feature-flag';

const Toggle = () => {
  const { feature, toggleFeature } = useFeature('dark-mode');
  return <Switch checked={feature?.enabled} onChange={() => toggleFeature()} />;
};

作用

说明: 要求数 @equinor/fusion-framework-module-roles 在申请中或父母关系 框架范围.

import { enableRoles } from '@equinor/fusion-framework-module-roles';

export const configure: AppModuleInitiator = (configurator) => {
  enableRoles(configurator);
};
import { useAccessRole } from '@equinor/fusion-framework-react-app/roles';

const ReportsAccess = ({ claimableRoleId }: { claimableRoleId: string }) => {
  const role = useAccessRole('Reports.Read');

  if (role.isChecking) return <Spinner />;
  if (role.checkError) return <ErrorMessage error={role.checkError} />;
  if (role.hasAccessRole) return <Reports />;

  /** Consumes the event-handler rejection; activationError below owns the visible failure. */
  const handleActivate = (): void => {
    void role
      .activateClaimableRoleAssignment({
        assignmentId: claimableRoleId,
        reason: 'Open reports',
        hours: 2,
      })
      .catch(() => undefined);
  };

  return role.hasClaimableRoleAssignmentForAccessRole ? (
    <>
      {role.activationError ? <p role="alert">{String(role.activationError)}</p> : null}
      <button disabled={role.isActivating} onClick={handleActivate}>
        Claim access
      </button>
    </>
  ) : null;
};

useAccessRole 安装时检查确切的存取作用名称,并在索赔成功后再次检查. 检查和索赔业务暴露出单独的装载和出错状态. activateClaimableRoleAssignment 拒绝失败和设置 activationError; 事件处理器必须消耗 拒绝并让突变出错,使用户可以重试.

书签

import { useCurrentBookmark } from '@equinor/fusion-framework-react-app/bookmark';

const BookmarkView = () => {
  const { currentBookmark } = useCurrentBookmark();
  return <pre>{JSON.stringify(currentBookmark, null, 2)}</pre>;
};

设置

import { useAppSetting } from '@equinor/fusion-framework-react-app/settings';

const ThemePicker = () => {
  const [theme, setTheme] = useAppSetting('theme', 'light');
  return <button onClick={() => setTheme('dark')}>Go dark</button>;
};

环境变量

import { useAppEnvironmentVariables } from '@equinor/fusion-framework-react-app';

const EnvInfo = () => {
  const env = useAppEnvironmentVariables();
  if (!env.complete) return <p>Loading…</p>;
  return <pre>{JSON.stringify(env.value, null, 2)}</pre>;
};

测试

测试公用事业renderAppHook, (中文(简体) ), renderAppComponent, (中文(简体) ), testApp插件 解析一个应用程序自己的显示/配置为虚拟模块)已移动到自己的软件包, @equinor/fusion-framework-vitest-plugin-react-app —— 说 查看软件包的 README 用于使用 .

API 参考

核心出口(主要切入点)

导出说明
renderApp从组件和可选配置回调创建挂载函数
makeComponentLazily 初始化模块并在框架提供者中包裹一个组件
createComponent(折旧) 工厂返回a ComponentRenderer
createLegacyApp(折旧) 遗留的Fusion CLI 应用程序的包装器
renderComponent下级助手: 挂载 a ComponentRenderer 通过 createRoot
useAppModule(key)按键返回单个模块实例
useAppModules()返回所有已关闭的应用程序模块
useAppEnvironmentVariables()应用环境配置的可观测状态

分路径入口

路径主要出口
/msaluseCurrentAccount, (中文(简体) ), useAccessToken, (中文(简体) ), useToken
/httpuseHttpClient (再出口)
/http/selectors反应选择器公用事业
/contextuseCurrentContext, (中文(简体) ), useContextProvider, (中文(简体) ), useFrameworkCurrentContext
/navigationuseRouter, (中文(简体) ), useNavigationModule
/feature-flagenableFeatureFlag, (中文(简体) ), useFeature
/rolesuseAccessRole
/bookmarkenableBookmark, (中文(简体) ), useCurrentBookmark, (中文(简体) ), useBookmark
/settingsuseAppSetting, (中文(简体) ), useAppSettings
/analyticsuseTrackFeature
/help-centeruseHelpCenter
/apploaderApploader, (中文(简体) ), useApploader
/frameworkuseFramework, (中文(简体) ), useCurrentUser, (中文(简体) ), useFrameworkHttpClient
/widget部件切入点

配置

应用程序配置通过调用完成 renderApp (或 makeComponent) (中文(简体) ). 回调收到一个 IAppConfigurator 使用每个模块的构建器:

const configure: AppModuleInitiator = (configurator) => {
  // HTTP clients
  configurator.configureHttpClient('my-api', { baseUri: '...' });

  // Feature flags
  enableFeatureFlag(configurator, [{ key: 'beta', title: 'Beta' }]);

  // Navigation, context, etc. — see module docs
};

MSAL / auth 模块由主机门户配置并自动提升为应用. 执行 没有 在应用程序代码中配置它 .

版本与发布记录

@equinor/fusion-framework-react-app 共发布 431 个版本,首次发布于 2022/01/14;过去 12 个月发布了 62 个版本。

版本发布日期距今
14.3.9latest2026/11/121 天前
14.3.9-next.0next2026/11/112 天前
14.3.82026/11/112 天前
14.3.8-next.22026/10/2915 天前
14.3.8-next.12026/10/2816 天前
14.3.8-next.02026/10/2816 天前

其他发布通道:apploader → 6.2.0-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9,cli-search-index → 8.0.1-cli-search-index.0,msal-v5 → 9.0.0-msal-v5.1,trusted-publishing-20261015 → 14.3.5-trusted-publishing-20261015-9dfe7602cd2a49a8a9df00d62c26e7304a82a85a,next → 14.3.9-next.0。

关于 @equinor/fusion-framework-react-app 的常见问题

如何安装 @equinor/fusion-framework-react-app?

在项目目录运行 npm install @equinor/fusion-framework-react-app,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18.0.0 || ^19.0.0)、@equinor/fusion-framework-module-msal(^12.1.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@equinor/fusion-framework-react-app 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@equinor/fusion-framework-react-app 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@equinor/fusion-framework-react-app 可以商用吗?

@equinor/fusion-framework-react-app 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@equinor/fusion-framework-react-app 的下载量有多少?

根据 npm 官方下载统计,@equinor/fusion-framework-react-app 在 2026/10/14 – 2026/11/12 这 30 天内被下载 8,095 次,日均约 270 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@equinor/fusion-framework-react-app 还在维护吗?

最新版本 14.3.9 发布于 2026/11/12(1 天前);至今共发布 431 个版本,其中过去 12 个月发布了 62 个;首次发布于 2022/01/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。