React
Getting started
Let's create a little app to demonstrate how to use React in flecks:
- npm
npm init @flecks/app react-test
cd react-test
We'll also create a little fleck to hold our root component:
- npm
npm init @flecks/fleck -w packages/root
We'll add the react
fleck to our new fleck:
cd packages/root
- npm
npx flecks add @flecks/react
We add @flecks/react
to packages/root
instead of our application directory so that our new
fleck encapsulates all the dependencies it needs. You can distribute your flecks to others if you
do this right!
Add a root component
Let's implement a hook to add a component to @flecks/react
's root components:
import Component from './component';
export const hooks = {
'@flecks/react.roots': () => Component,
};
Let's also add our component source file:
import {React} from '@flecks/react';
function Component() {
return <p>hello world (from React)</p>;
}
export default Component;
You may notice we imported React
from @flecks/react
instead of react
. This is provided as a
convenience. flecks is a very dynamic system and it may also be possible to load multiple React
versions on your page.
Using @flecks/react
makes sure your components are all using the same instance of React
.
Go check it out
Start your application:
- npm
npm run start
Visit your website in your browser and you will see the hello world message!
If you disable JavaScript in your browser and reload the page you will still see the message. This
is because Server-Side Rendering (SSR) is enabled by default! If you don't want this, update your
build/flecks.yml
:
'@flecks/core':
id: react-test
'@flecks/react':
ssr: false
'@flecks/server': {}
'@react-test/root:./packages/root/src': {}
Now if you visit the page with JavaScript disabled, you will get a white page.
Hot module reloading
You'll notice that if you edit your component, the changes are immediately reflected on the page. This is because we have HMR support in our application!
Routing
flecks provides @flecks/react/router
which implements server and client routing using
React Router's <RouterProvider>
.
Just add it to flecks.yml
:
'@flecks/core':
id: react-test
'@flecks/react': {}
'@flecks/react/router': {}
'@flecks/server': {}
'@react-test/root:./packages/root/src': {}
Filetree routing
It is possible to define your routes as a file structure. A helper is provided to build a routes object from your file structure:
import {createRoutesFromContext} from '@flecks/react/router';
export const hooks = {
'@flecks/react/router.routes': () => (
createRoutesFromContext(require.context('./routes'))
),
};
Supposing your ./routes
directory was structured as:
routes
├─ index.jsx
├─ [...catchall].jsx
├─ -optional.jsx
├─ -[optionalDynamic].jsx
├─ about.jsx
└─ team/
└─ [teamId]/
├─ index.jsx
└─ edit.jsx
Your routes object would look like:
[
{path: '/', ...},
{path: '*', ...},
{path: '/about', ...},
{path: '/optional?', ...},
{path: '/:optionalDynamic?', ...},
{
path: '/team', ...,
children: [
{
path: ':teamId', ...
},
{
path: ':teamId/edit', ...
},
],
},
]
Each route object has a ...
in the diagram above because each module is import()
ed and the
exports are mixed in to the Route. Route modules should probably at least
export function Component() { ... }
, but may export any of
the Route props.
You may export a default
export which will be used as the component. An explicit named
Component
export will take precedence.
Selecting the root
There can only be one root of your router tree. Supposing you implemented
@flecks/react/router.routes
in your fleck called @my/routes-root
, you would set the following
configuration in build/flecks.yml
to use your fleck's routes as the root:
'@flecks/react/router':
root: '@my/routes-root'
Hooks
useFlecks()
You may use this hook from your components to gain access to the flecks
instance.
Example:
function Component() {
const flecks = useFlecks();
const id = flecks.get('@flecks/core.id');
return <p>Your application ID is {id}</p>;
}
useEvent(object, eventName, fn)
object
The event emitter to listen to
eventName
The name of the event to listen for.
fn
The event handler to call.
Example:
function Component() {
const flecks = useFlecks();
const [isConnected, setIsConnected] = useState(false);
useEvent(flecks.socket, 'connect', () => {
setIsConnected(true);
});
useEvent(flecks.socket, 'disconnect', () => {
setIsConnected(false);
});
return <p>Socket is {isConnected ? 'connected' : 'disconnected'}.</p>;
}
usePrevious(value)
value
The value whose previous value we're interested in.
See: https://blog.logrocket.com/accessing-previous-props-state-react-hooks/