React content management Framework
This is a framework to help you to build configurable React App.
It provides a set of base APIs and patterns.
Requirements
Before trying CMF you must know:
You must understand all the following words: pure component, action creator, reducer, put, takeEvery, fromJS, ...
What is react-cmf
It's a framework. It is the results of the years of experience with react ecosystem at Talend. The goal is to provide one way to do the things keeping best pratices in mind.
Working with react-cmf
If you tried to work with the required addons listed above you will do some repetitive tasks and some boiler plate every time and on each components.
When working with a framework like angular you have the tools plus a guideline on how to use them. With CMF the idea is the same. Provide the good set of tools plus the guideline.
To start a project using react-cmf you can use bootstrap API.
Working with react-cmf means:
- you write a set of configurable pure component connected using
cmfConnect
- you configure them using the settings
- events are handled in a saga (effects are the way to write business code)
Side by side with angular 1:
- components are React cmfConnected (pure) component
- services are sagas
- controllers are containers
UI sends actions into redux which are handled by sagas.
cmfConnect higher order component
cmfConnect
create a component with all CMF features charged in it.
Under the hood it uses the connect function and create a container.
Once your component is connected:
- you can read data from the store using expression
- you can dispatch actions using onEvent handler
Read more about cmfConnect
Store structure
CMF uses react-redux store with the following structure
- root
- cmf
- collections
- components
- settings
- cmf
Collections and components use Immutable data structure.
ComponentState Management
Component state can be easily stored in cmf state, each are identified by their name and an unique key, so component state can be stored and reused later.
We give you the choice to use either:
- CMF redux state (this.props.state && this.props.setState)
- React component state (this.state && this.setState)
Warning: you should use the redux state except for part that require lots of mutation without sharing. For example for Forms you should prefer to use the internal React component state.
Collections management
Manage a local cache of your business data. You can connect your component to give it access to your data and being able to dispatch action to let CMF reducers write them.
You can dispatch some actionCreators in api.actions.collections for that.
Settings
We don't want to create a PR, merge, build to change a label of a button right? With CMF you can describe all your app just using json.
The json looks like this:
{
"props": {
"App#default": {
"saga": "bootstrap"
},
"Navbar#default": {
"brand": "Talend",
"left": [{ "component": "Button", "componentId": "help" }]
},
"Button#help": {
"id": "help",
"label": "help",
"payload": {
"type": "MENU_HELP",
"cmf": {
"routerPush": "/help"
}
}
}
}
}
Scripts
When you have cmf in you project, it adds scripts in your node_modules/.bin
Tips you should add node_modules/bin
folder into your path.
So you can use them either in CLI or in npm scripts.
Tests & mocks
When you are in the context of CMF and you want to test your component you will need to mock some stuff (context, ...).
We want testing experience to be easy so CMF provides some mocks for you.
import React from 'react';
import { Provider } from 'react-cmf/lib/mock';
import { render, screen } from '@testing-library/react';
import AppMenu from './AppMenu.component';
describe('AppMenu', () => {
it('should render', () => {
render(
<Provider>
<AppMenu />
</Provider>,
);
expect(screen.getByRole('button')).toBeDefined();
});
});
This way MyComponent may request for the following context:
- registry
- store
you may change the following using simple props:
- store
- state
- registry
The http saga
The http saga is here to help execute some http requests from inside any saga.
By default, the credentials option of fetch is set to includes
and not the default same-origin
.
It allows to share the credentials (cookies) in cross origin requests.
See credentials in the fetch() global function for more details.