React Hooks
note
React Hooks are only supported in Functional React Components!
useAgile()
â
The useAgile()
React Hook binds/subscribes AgileTs States to a Functional React Component for reactivity.
This binding ensures that the Component re-renders whenever a bound State changes.
We can flexibly bind any Agile Sub Instances
(like States or Collections) to any React Component.
const myCoolState = useAgile(MY_COOL_STATE);
The useAgile()
Hook returns the current value
of the provided State
and not the State Instance itself.
// -- core.js --------------------------------------------------
const MY_STATE = createState('jeff');
// -- MyComponent.jsx ------------------------------------------
const myState = useAgile(MY_STATE);
console.log(myState); // Returns 'jeff'
đ Arrayâ
We can also pass an array of States to the useAgile()
Hook.
useAgile([MY_COOL_STATE1, MY_COOL_STATE2]);
Then useAgile()
returns an array of State values
matching the specified State Instances.
This array can be destructured in order to easily access the individual State values
// -- core.js --------------------------------------------------
const MY_STATE = createState('jeff');
const MY_STATE_2 = createState('frank');
// -- MyComponent.jsx ------------------------------------------
const [myState, myState2] = useAgile([MY_STATE, MY_STATE_2]);
console.log(myState); // Returns 'jeff'
console.log(myState2); // Returns 'frank'
Binding multiple States to a React Component using a single useAgile()
Hook has one advantage.
It can reduce the number of triggered re-render events by batching re-render jobs.
Thereby, simultaneously triggered re-render events of different State Instances
are combined into one single (combined) re-render event
if these States share the same Subscription Container
.
Each useAgile()
Hook creates its own Subscription Container
and registers it with AgileTs.
Simply put Subscription Container
serve as an interface to React-Components for AgileTs.
đ Subscribable Instancesâ
Not only AgileTs States can be bound to React Components via useAgile()
,
but also all other Agile Sub Instances
that contain an Observer
.
const [myCollection, myGroup, myState] = useAgile([MY_COLLECTION, MY_GROUP, MY_STATE]);
Instances that contain an Observer
are, for example:
State
â// -- core.js --------------------------------------------------
const MY_STATE = createState('jeff');
// -- MyComponent.jsx ------------------------------------------
const myState = useAgile(MY_STATE);
console.log(myState); // Returns 'jeff'Computed
â// -- core.js --------------------------------------------------
const MY_COMPUTED = createComputed(() => 'hello there');
// -- MyComponent.jsx ------------------------------------------
const myComputed = useAgile(MY_COMPUTED);
console.log(myComputed); // Returns 'hello there'Collection
âNote: A Collection doesn't contain directly an
Observer
. ButuseAgile()
is smart enough, to identify a Collection and binds thedefualt
Group to the React Component instead. Thedefault
Group represents the default pattern of the Collection.// -- core.js --------------------------------------------------
const MY_COLLECTION = createCollection({
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
});
// -- MyComponent.jsx ------------------------------------------
const myCollection = useAgile(MY_COLLECTION);
console.log(myCollection); // Returns (see below)
// '[{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]'Group
â// -- core.js --------------------------------------------------
const MY_COLLECTION = createCollection({
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
});
const MY_GROUP = MY_COLLECTION.createGroup('myGroup', [3, 1]);
// -- MyComponent.jsx ------------------------------------------
const myGroup = useAgile(MY_GROUP);
console.log(myGroup); // Returns '[{id: 3, name: 'c'}, {id: 1, name: 'a'}]'Selector
â// -- core.js --------------------------------------------------
const MY_COLLECTION = createCollection({
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
});
const MY_SELECTOR = MY_COLLECTION.select(2);
// -- MyComponent.jsx ------------------------------------------
const mySelector = useAgile(MY_SELECTOR);
console.log(mySelector); // Returns '{id: 2, name: 'b'}'Item
â// -- core.js --------------------------------------------------
const MY_COLLECTION = createCollection({
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
});
const MY_ITEM = MY_COLLECTION.getItem(3);
// -- MyComponent.jsx ------------------------------------------
const myItem = useAgile(MY_ITEM);
console.log(myItem); // Returns '{id: 3, name: 'c'}'
đ´ Exampleâ
đĻ Typescriptâ
The useAgile()
Hook is almost 100% typesafe.
// -- core.js --------------------------------------------------
const NUMBER_STATE = createState(0);
const STRING_STATE = createState('hello there');
// -- MyComponent.jsx ------------------------------------------
const [numberState, stringState] = useAgile([NUMBER_STATE, STRING_STATE]);
console.log(typeof numberState); // Returns 'number'
console.log(typeof stringState); // Returns 'string'
đ Propsâ
Prop | Type | Description | Required |
---|---|---|---|
deps | Array<SubscribableAgileInstancesType> | SubscribableAgileInstancesType | Agile Sub Instances to be bound to the Functional Component. | Yes |
config | AgileHookConfigInterface | Configuration | No |
SubscribableAgileInstancesTypeâ
type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
đ Returnâ
The useAgile()
Hook returns the current output
or if the Instance has no output
the current value
of the specified Agile Sub Instance.
// -- core.js -------------------------------------------------
const MY_STATE = createState('jeff');
// -- MyComponent.jsx ------------------------------------------
const myState = useAgile(MY_STATE);
console.log(myState); // Returns 'jeff'
When passing multiple Agile Sub Instances,
an array of outputs
/values
matching the passed Instances is returned.
// -- core.js --------------------------------------------------
const MY_STATE = createState('jeff');
const MY_STATE_2 = createState('frank');
// -- MyComponent.jsx ------------------------------------------
const [myState, myState2] = useAgile([MY_STATE, MY_STATE_2]);
console.log(myState); // Returns 'jeff'
console.log(myState2); // Returns 'frank'
useProxy()
â
warning
Requires an additional package called @agile-ts/proxytree
!
The useProxy()
is in its basic functionality equivalent to the useAgile()
Hook.
It binds/subscribes AgileTs States to a Functional React Component for reactivity.
However, it has one advantage in terms of performance.
Because it only re-renders the React Component when an actual accessed property changes.
This is accomplished by warping a Proxy()
around the returned State value object/s.
Through this Proxy, AgileTs is able to exactly track accessed properties in the React Component
and can construct paths to these. Based on these paths, it can select the particular accessed properties.
With the useAgile()
Hook, the Component would always be re-rendered on a subscribed State value change,
regardless of whether the changed property value was accessed in the Component or not.
đ Subscribable Instancesâ
Not only AgileTs States can be bound to React Components via useProxy()
,
but also all other Agile Sub Instances
that contain an Observer
.
const [myCollection, myGroup, myState] = useProxy([MY_COLLECTION, MY_GROUP, MY_STATE]);
However, a Javascript Proxy
can only be wrapped around values of the type object
.
Instances that are not of the type object are treated as in useAgile()
.
đ´ Exampleâ
đĻ Typescriptâ
The useProxy()
Hook is almost 100% typesafe.
đ Propsâ
Prop | Type | Description | Required |
---|---|---|---|
deps | Array<SubscribableAgileInstancesType> | SubscribableAgileInstancesType | Agile Sub Instances to be bound to the Functional Component. | Yes |
config | AgileHookConfigInterface | Configuration | No |
SubscribableAgileInstancesTypeâ
type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
đ Returnâ
The useProxy()
Hook returns the current output
or if the Instance has no output
the current value
of the specified Agile Sub Instance.
// -- core.js -------------------------------------------------
const MY_STATE = createState('jeff');
// -- MyComponent.jsx ------------------------------------------
const myState = useProxy(MY_STATE);
console.log(myState); // Returns 'jeff'
When passing multiple Agile Sub Instances,
an array of outputs
/values
matching the passed Instances is returned.
// -- core.js --------------------------------------------------
const MY_STATE = createState({id: 1: name: 'jeff'});
const MY_STATE_2 = createState('frank');
// -- MyComponent.jsx ------------------------------------------
const [myState, myState2] = useProxy([MY_STATE, MY_STATE_2]);
console.log(myState); // Returns '{id: 1: name: 'jeff'}'
console.log(myState2); // Returns 'frank'
useSelector()
â
The useSelector()
React Hook binds/subscribes a part
of an AgileTs State to a Functional React Component for reactivity.
This binding ensures that the Component re-renders whenever the bound State part/property changes.
The to bind part is selected via a selector function specified as second parameter.
const myName = useAgile(MY_USER, (v) => v.name);
đ Subscribable Instancesâ
Not only parts of AgileTs States can be bound to React Components via useSelector()
,
but also parts of all other Agile Sub Instances
that contain an Observer
.
const myItem1 = useSelector(MY_COLLECTION, (v) => v['item1']);
đ´ Exampleâ
đĻ Typescriptâ
The useSelector()
Hook isn't completely typesafe yet.
const selectedValue = useSelector(MY_STATE, (v) => v.name);
We are still figuring out how to automatically detect and return the selected property type. As an override, you can also specify the individual types as generics.
useSelector<typeof MY_STATE.value, string>(MY_STATE, (v) => v.name);
Or explicitly assign the desired type to the return value with the as
keyword.
useSelector(MY_STATE, (v) => v.name) as string;
đ Propsâ
Prop | Type | Description | Required |
---|---|---|---|
dep | SubscribableAgileInstancesType | Agile Sub Instance to be passed into the specified selector method. | Yes |
selector | SelectorMethodType | Selector method to select the part/property of the specified Agile Sub Instance value to be bound to the Functional Component. | Yes |
config | AgileHookConfigInterface | Configuration | No |
SubscribableAgileInstancesTypeâ
type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
SelectorMethodTypeâ
type SelectorMethodType<T = any> = (value: T) => any;
đ Returnâ
The useSelector()
Hook returns the selected property (based on the selector method)
of the specified Agile Sub Instance.
// -- core.js -------------------------------------------------
const MY_STATE = createState({id: 10, name: 'jeff', age: 10});
// -- MyComponent.jsx ------------------------------------------
const myName = useSelector(MY_STATE, (v) => v.name);
console.log(myName); // Returns 'jeff'
useValue()
â
The useValue()
is in its basic functionality equivalent to the useAgile()
Hook.
It binds/subscribes AgileTs States to a Functional React Component for reactivity.
However, it differs in on key area,
because it explicitly binds the value
of a State or other Agile Sub Instances
to the Component instead of preferring the ouptut
. Normally (like in the useAgile()
Hook),
the output
of an Agile Sub Instance has a higher weight than the value
.
For example if we bind a Collection with the useAgile()
Hook to a React Component,
the output
of the Collection is bound to the Component.
When we use the useValue()
Hook instead, the value
of the Collection is bound to the Component.
// -- core.js -------------------------------------------------
const MY_COLLECTION = createCollection({
initialData: [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]
});
// -- MyComponent.jsx ------------------------------------------
const collectionValue = useValue(MY_COLLECTION);
console.log(collectionValue); // Returns '[1, 2, 3]'
const collectionOutput = useAgile(MY_COLLECTION);
console.log(collectionOutput); // Returns (see below)
// '[{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 3, name: 'c'}]'
đ Subscribable Instancesâ
Not only AgileTs States can be bound to React Components via useValue()
,
but also all other Agile Sub Instances
that contain an Observer
.
const [myCollection, myGroup, myState] = useValue([MY_COLLECTION, MY_GROUP, MY_STATE]);
đ´ Exampleâ
đĻ Typescriptâ
The useValue()
Hook is almost 100% typesafe.
đ Propsâ
Prop | Type | Description | Required |
---|---|---|---|
deps | Array<SubscribableAgileInstancesType> | SubscribableAgileInstancesType | Agile Sub Instances to be bound to the Functional Component. | Yes |
config | AgileHookConfigInterface | Configuration | No |
SubscribableAgileInstancesTypeâ
type SubscribableAgileInstancesType = State | Collection | Observer | undefined;
đ Returnâ
The useValue()
Hook returns the current value
of the specified Agile Sub Instance.
// -- core.js -------------------------------------------------
const MY_COLLECTION = createCollection({initialData: [
{id: 1, name: 'jeff'}, {id: 2, name: 'hans'}
]});
// -- MyComponent.jsx ------------------------------------------
const myValue = useValue(MY_COLLECTION);
console.log(myValue); // Returns '[1, 2]'
When passing multiple Agile Sub Instances,
an array of values
matching the passed Instances is returned.
// -- core.js --------------------------------------------------
const MY_COLLECTION = createCollection({initialData: [
{id: 1, name: 'jeff'}, {id: 2, name: 'hans'}
]});
const MY_STATE_2 = createState('frank');
// -- MyComponent.jsx ------------------------------------------
const [myValue, myState2] = useValue([MY_COLLECTION, MY_STATE_2]);
console.log(myValue); // Returns '[1, 2]'
console.log(myState2); // Returns 'frank'
useWatcher()
â
The useWatcher()
React Hook lets us easily observe a State for changes.
Thereby is the provided callback
function fired on every State value
mutation.
Such mutation occurs when we, for example, update the State value
from 'jeff' to 'hans'.
useWatcher(MY_STATE, (value) => {
console.log(value); // Returns current State Value
});
The useWatcher()
Hook is a synonym to the watch()
method.
However, it has some advantages within React Components:
- It automatically cleans up the created watcher callback when the React Component unmounts
- Is nicer to read in 'UI-Component-Code'
đ´ Exampleâ
đĻ Typescriptâ
The useWatcher()
Hook is almost 100% typesafe.
đ Propsâ
Prop | Type | Description | Required |
---|---|---|---|
state | State<T> | State to which the specified watcher callback belongs. | Yes |
callback | StateWatcherCallback<T> | A function to be executed on each State value change. | Yes |
đ Returnâ
void