行为
使用行为,您可以实现自定义场景逻辑,这些逻辑将作为副作用执行。行为对于执行副作用很有用,例如有条件地隐藏场景上的元素或在场景对象之间附加共享功能。
定义行为
行为可以通过两种方式实现
- 作为在父元素激活时被调用的纯函数。
- 作为在父元素激活时被激活的场景对象。
可以使用 $behaviors
状态属性将行为附加到场景对象。例如,您可以将行为附加到 SceneQueryRunner
const queryRunner = new SceneQueryRunner({
$behaviors: [
/* list of behaviors */
],
datasource: {
type: 'prometheus',
uid: 'gdev-prometheus',
},
queries: [
{
refId: 'A',
range: true,
format: 'time_series',
expr: 'rate(prometheus_http_requests_total[5m])',
},
],
});
行为作为纯函数
行为可以实现为一个无状态函数,该函数在行为父元素激活时被调用。此函数可以返回一个在父元素停用时被调用的停用处理程序。
下面您将找到一个简单的无状态行为,它将在行为的父元素激活/停用或其状态更改时在开发者控制台中记录。
const StatelessLoggerBehavior = (parent: SceneObject) => {
console.log(`${parent.state.key} activated`);
parent.subscribeToState(() => {
console.log(`${parent.state.key} state changed`);
});
return () => {
console.log(`${parent.state.key} deactivated`);
};
};
行为作为场景对象
将行为实现为场景对象与实现自定义场景对象完全相同。下面的示例说明了来自先前示例的扩展日志记录行为,该行为将在场景对象激活/停用时在开发者控制台中记录,并根据提供的配置批量记录父状态更新日志
interface StatefulLoggerBehaviorState extends SceneObjectState {
// Size of the batch of state updates
batchStateUpdates: number;
}
class StatefulLoggerBehavior extends SceneObjectBase<StatefulLoggerBehaviorState> {
private _batchedStateUpdates: Array<SceneObjectState> = [];
constructor(state: Partial<StatefulLoggerBehaviorState>) {
super({
batchStateUpdates: 5,
...state,
});
this.addActivationHandler(this._onActivate);
}
private _onActivate = () => {
const parent = this.parent;
if (!parent) {
throw new Error('LoggerBehavior must be attached to a parent object');
}
console.log(`StatefulLoggerBehavior: ${parent.state.key} activated`);
parent.subscribeToState(() => {
this._batchedStateUpdates.push(parent.state);
if (this._batchedStateUpdates.length === this.state.batchStateUpdates) {
console.log(`StatefulLoggerBehavior: ${parent.state.key} state changed batch`, this._batchedStateUpdates);
this._batchedStateUpdates = [];
}
});
return () => {
console.log(`StatefulLoggerBehavior: ${parent.state.key} deactivated`);
};
};
}
内置行为
场景库附带以下内置行为
ActWhenVariableChanged
在变量更改时执行副作用。
用法
假设场景中存在一个名为 myVariable
的变量,您可以配置在它的值更改时执行的副作用
import { behaviors } from '@grafana/scenes';
const logWhenVariableChanges = new behaviors.ActWhenVariableChanged({
variableName: 'myVariable',
onChange: (variable) => {
console.log(`myVariable value changed: ${variable.state.value}`);
},
});
CursorSync
创建共享游标范围,用于跨多个面板配置游标同步。
用法
在下面的示例中,CursorSync
行为用于同步场景中所有面板的游标
import {
behaviors,
EmbeddedScene,
PanelBuilders,
SceneFlexItem,
SceneFlexLayout,
SceneQueryRunner,
SceneTimeRange,
} from '@grafana/scenes';
const httpRequests = new SceneQueryRunner({
datasource: {
type: 'prometheus',
uid: 'gdev-prometheus',
},
queries: [
{
refId: 'A',
range: true,
format: 'time_series',
expr: 'rate(prometheus_http_requests_total[5m])',
},
],
});
const cpuUsage = new SceneQueryRunner({
datasource: {
type: 'prometheus',
uid: 'gdev-prometheus',
},
queries: [
{
refId: 'A',
expr: 'avg by (job, instance, mode) (rate(node_cpu_seconds_total[5m]))',
},
],
});
const scene = new EmbeddedScene({
$timeRange: new SceneTimeRange({ from: 'now-5m', to: 'now' }),
$behaviors: [new behaviors.CursorSync({ key: 'cursor-sync-scope', sync: DashboardCursorSync.Tooltip })],
body: new SceneFlexLayout({
direction: 'row',
children: [
new SceneFlexItem({
width: '50%',
height: 300,
body: PanelBuilders.timeseries().setData(httpRequests).setTitle('HTTP Requests').build(),
}),
new SceneFlexItem({
width: '50%',
height: 300,
body: PanelBuilders.timeseries()
.setTitle('CPU Usage')
.setTimeRange(new SceneTimeRange({ from: 'now-6h', to: 'now' }))
.setData(cpuUsage)
.build(),
}),
],
}),
});