Getting Started
React Eagle Eye is an independent state manager, which once created, can be deployed at any location in all parts of the application. The React Eagle Eye context comes in two usage modes: the CSR and the SSR modes.
npm install --save @webkrafters/react-eagleeyeCreating the React Eagle Eye store
To obtain a fresh context store, just obtain a React Eagle Eye instance in a manner compatible with your application mode, shown as follows:MODE:
1
2
3
4
5
6
import { createEagleEye } from '@webkrafters/react-eagleeye';
const MyContext = createEagleEye({
a: { b: { c: null, x: { y: { z: [ 2022 ] } } } }
});
export const useMyStream = MyContext.useStream;
export default MyContext;MODE:
1
2
3
4
5
6
7
8
9
10
11
import React, { useEffect, useState } from 'react';
import MyContext from './context';
import Ui from './ui';
const Container = ({ ageInMinutes: c = 0 }) => {
useEffect(() => MyContext.store.setState({ c: ageInMinutes }), [ ageInMinutes ]);
return ( <Ui /> );
};
Container.displayName = 'Container';
export default Container;Joining the React Eagle Eye change stream
React Eagle Eye change stream is a reactive store whose data are automatically changing to reflect most recent changes affecting them.
There are two ways of joining the React Eagle Eye change stream: The HOC method and the React Hook method.
Let's tackle the HOC method first. This method uses the context's internal mechanism to bind a component automatically to the context. In a standard SPA (i.e. CSR mode), the
connect(...) property holding an HOC function wires up the context change stream to your consumer component. In a universal SPA (i.e. SSR mode), the stream(...) property holding an into(...) method accomplishes the same.It embodies the "set-it-and-forget-it" paradigm. Just set up a list of property paths to state slices to observe (see Selector Map). The context takes care of the rest.
The following is a sample of the HOC consumer method.
MODE:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import React, { useCallback, useEffect } from 'react';
import MyContext from './context';
export const YearText = ({ data }) => ( <div>Year: { data.year }</div> );
export const YearInput = ({ data, resetState, setState }) => {
const onChange = useCallback( e => setState({
a: { b: { x: { y: { z: { 0: e.target.value } } } } }
}), [ setState ]);
useEffect(() => {
data.year > 2049 && resetState([ 'a.b.c' ]);
}, [ data.year ]);
return ( <div>Year: <input type="number" onChange={ onChange } /></div> );
};
const withConnector = MyContext.connect({ year: 'a.b.x.y.z[0]' });
const Client1 = withConnector( YearText );
const Client2 = withConnector( YearInput );
const Ui = () => (
<div>
<Client1 />
<Client2 />
</div>
);
export default Ui;Joining the React Eagle Eye change stream (React Hook method)
The following shows how to join the React Eagle Eye stream using the hook method.
This method uses the context's
useStream(...) property holding the hook function to expose the context change stream to your consumer component.Note: In addition to setting up a map of property paths to state slices to observe (see Selector Map), the consumer compoent may have to be wrapped in a React.memo(...) HOC to shield it from cascading rerenders from parent/anscestor components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React, { memo, useCallback, useEffect } from 'react';
import { useMyStream } from './context';
const selectorMap = { year: 'a.b.x.y.z[0]' };
const Client1 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
const { data } = useMyStream( selectorMap );
return ( <div>Year: { data.year }</div> );
});
const Client2 = memo(() => { // memoize to prevent 'no-change' renders from the parent.
const { data, setState, resetState } = useMyStream( selectorMap );
const onChange = useCallback( e => setState({
a: { b: { x: { y: { z: { 0: e.target.value } } } } }
}), [ setState ]);
useEffect(() => {
data.year > 2049 && resetState([ 'a.b.c' ]);
}, [ data.year ]);
return ( <div>Year: <input type="number" onChange={ onChange } /></div> );
});
const Ui = () => (
<div>
<Client1 />
<Client2 />
</div>
);
export default Ui;The React Eagle Eye runs decoupled from its embodying application, simply providing an active place for the application to accumulate, access, update and delete its various states as needed in ways that maintains immutabiliity and integrity of state data. The following is a contrived snippet to demonstrate.
MODE:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import React, { useEffect, useState } from 'react';
import Container from './container';
const MILLIS_PER_MINUTE = 6e4;
let numCreated = 0;
const App = () => {
const [ age, updateAge ] = useState( 0 );
const [ testNumber ] = useState( () => ++numCreated );
useEffect(() => {
const t = setTimeout(
() => updateAge( age => age + 1 ),
MILLIS_PER_MINUTE
);
return () => clearTimeout( t );
}, [ age ]);
return (
<div>
<h2>App instance #: { testNumber }</H2>
<Container ageInMinutes={ age } />
</div>
);
}
export default App;