Action to update arbitrary slice of component state
Overview
Action/reducer pairs are used to update information about a component in Redux state. For more information about how this process works please refer to this document. Generally, consumers of a UiSdlComponent will only have access to the actions defined on that component in order to update its state. These actions are well defined and target specific end-to-end use cases. This ensures application developers can achieve rich functionality with minimal configuration. The trade-off is that typically, application developers will not directly interact with specific parts of the Redux state.
For exceptional use cases, UI Framework provides an action that allows you to update any arbitrary slice of a component state. This document will go over what that action is, how to use it, and why its use should be avoided if at all possible.
Why to avoid
To start, using this action will be 100% at your own risk. This section will go over the multitude of reasons not to use this action.
Changing component configurations can lead to unintended consequences
The C3 UI Framework provided components often contain complex logic, so arbitrarily changing parts of a component's configuration may cause a chain reaction of other changes that were not intended.
Some effects require multiple changes
With actions defined on the component, the reducer may already be changing multiple parts of the component's state to achieve the desired effect, but when doing this without full context, it can be difficult to know when multiple things need to be changed.
Let's take the example of changing the metricName used for a UiSdlTimeseriesLineBarChart. Although possible to change only the metricName, it can lead to flickering as the component first re-renders with the metric name changed but with the old data, causing the logic to match lines/bars with the correct axes to fail. It will then re-render again after the data is received for the new configuration, and it will return to working as expected. In this case, it would be recommended to also clear existing data when changing the metricName to avoid these issues.
Performance issues
With changes such as the one mentioned above, you may experience performance issues as certain slices when updated arbitrarily may cause more re-renders than expected, leading to slowdowns.
GLOBAL_DANGEROUSLY_SET_ARBITRARY_COMPONENT_VALUE
The new UiSdlArbitraryComponentValueDangerouslySetAction has the suffix GLOBAL_DANGEROUSLY_SET_ARBITRARY_COMPONENT_VALUE. It expects three items in its payload.
- componentId -
string
- The ID of the component which needs its state updated.
- path -
[string]
- The path within the component to the slice that needs to be updated. For example to update
dataSpec.actionName, use['dataSpec', 'actionName'].
- value -
any
- The value to place at the designated path in state.
How to use
Since GLOBAL_DANGEROUSLY_SET_ARBITRARY_COMPONENT_VALUE is a global action, so it is available as an action type by users of the C3 UI Framework.
Examples
This example shows how to set a component Your.ComponentId to use fetch as the action for its dataSpec through a custom epic.
// EpicName.ts
import { of } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
import { Epic } from 'redux-observable';
import { ImmutableReduxState } from '@c3/ui/UiSdlConnected';
import { UiSdlReduxAction } from '@c3/types';
// eslint-disable-next-line import/prefer-default-export
export const epic: Epic<UiSdlReduxAction, UiSdlReduxAction, ImmutableReduxState> = (actionStream, _stateStream) =>
actionStream.pipe(
mergeMap(function (action: { [key: string]: unknown }) {
return of({
type: 'GLOBAL_DANGEROUSLY_SET_ARBITRARY_COMPONENT_VALUE',
payload: {
componentId: 'Your.ComponentId',
path: ['dataSpec', 'actionName'],
value: 'fetch'
},
});
}),
);This example will show you how to dispatch the action in a custom component. See this document for more information about creating custom components.
// CustomComponent.tsx
import { useDispatch } from '@c3/ui/UiSdlUseDispatch';
import * as React from 'react';
const CustomButton = (props: any) => {
const dispatch = useDispatch();
const clickHandler = () => {
const globalAction = {
type: 'GLOBAL_DANGEROUSLY_SET_ARBITRARY_COMPONENT_VALUE',
payload: {
componentId: 'Your.ComponentId',
path: ['dataSpec', 'actionName'],
value: 'fetch'
}
}
dispatch(globalAction);
}
return (
<button onClick={clickHandler}> Use Fetch </button>
)
}