https://github.com/Strikersoft/poa
Opinionated React framework
https://github.com/Strikersoft/poa
framework lerna mobx opinionated-react-framework poa react react-framework router
Last synced: 4 days ago
JSON representation
Opinionated React framework
- Host: GitHub
- URL: https://github.com/Strikersoft/poa
- Owner: Strikersoft
- License: mit
- Created: 2017-09-26T19:13:22.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2018-09-21T14:45:04.000Z (almost 8 years ago)
- Last Synced: 2025-10-28T05:27:41.747Z (8 months ago)
- Topics: framework, lerna, mobx, opinionated-react-framework, poa, react, react-framework, router
- Language: TypeScript
- Homepage:
- Size: 1.41 MB
- Stars: 8
- Watchers: 1
- Forks: 1
- Open Issues: 15
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: code-of-conduct.md
Awesome Lists containing this project
- awesome-github-projects - poa - Opinionated React framework ⭐8 `TypeScript` (📦 Legacy & Inactive Projects)
README
# Poa framework
[](https://github.com/prettier/prettier)
[](https://lernajs.io/)
## Gettings started
### Install
```bash
yarn add react @poa/core
```
### Opinionated
Poa — opinionated React framework.
What does opinionated mean?
* Framework will not suit for every case
* It has unique vision on how things should work
* #0CJS
* We hame some opinions on how things should work ;)
Since it is a framework, not a library, it bundled with all needed stuff to create small, medium and large projects.
### Getting started
We are assuming that you're using some official [starter kit](https://reactjs.org/community/starter-kits.html) (though it should work with custom setup as well).
TLDR; [https://codesandbox.io/s/yzzqk57lx](https://codesandbox.io/s/yzzqk57lx)
#### Basics
Initialize the Poa:
```js
// index.js
import { boot } from '@poa/core';
boot();
```
It should open a dummy Poa screen.
#### Adding some routes
Let's add React component first;
```js
// src/pages/home.page.js
import React from 'react';
import { Component } from '@poa/core';
class HomePage extends React.Component {
render() {
return
Heelo!
;
}
}
export default Component(/* additional config */)(HomePage);
```
Then let's declare our routing!
```js
// src/routes.js
import HomePage from './pages/home.page';
export const routes = [
{
path: '',
redirectTo: '/home'
},
{
path: '/home',
component: HomePage
}
];
```
Note, that we are using `redirectTo` functionality from mobx-little-route. (TODO: describe the Poa routing API)
The last thing, add your routes to Poa boot
```js
import { boot } from '@poa/core';
import { routes } from './routes';
boot({ router: { routes } });
```
Okay. Now on screen you will see you `HomePage` component and `/home` route;
#### Add localization
Let's define our locales first
```js
// src/locales/en.js
export const en = {
helloScreen: {
helloMessage: 'Jumbo jumbo!'
}
};
```
Then let's update our component
```js
// src/pages/home.page.js
import React from 'react';
import { Component } from '@poa/core';
class HomePage extends React.Component {
t; // injected by Poa
render() {
return
{this.t('helloMessage')}
;
}
}
export default Component({ namespaces: ['homeScreen'] })(HomePage);
```
Notice that we using `this.t(...)`. Poa gently inject translation function to your components if you use enhancer `Component(config)(ReactComponent)`
Also, we pass `namespaces` in the `Component({ namespaces: ['homeScreen'] })(HomePage)` poa component enhancer.
After this, pass localization into i18n config.
```js
// src/index.js
import { boot } from '@poa/core';
import { routes } from './routes';
import { en } from './locales/en';
boot({
router: { routes },
i18n: { lng: 'en', resources: { en } }
});
```
Notice, that in i18n you can pass any additional config that is supported by [i18next](https://www.i18next.com). We just wrap it API (TODO: describe the Poa internationalization API)
#### Add state managment
Let's add moar complexity.
Add initial state of your application.
```js
// src/stores/hello.state.js
export const initialState = {
dunnoState: false
};
```
Add some actions!
```js
// src/stores/hello.actions.js
import { createAction, addMutator, addSideEffects } from '@poa/state';
// action that can be dispatched with just functino invoking
export const dunnoAction = createAction('dunno', newValue => ({ newValue }));
// the only place where data can be changed
addMutator(dunnoAction, (payload, { store }) => {
store.dunnoState = payload.newValue;
});
// any side-effects
addSideEffects(dunnoAction, async (payload, { store }) => {
console.log('new store', store);
});
```
Add actions to our component
```js
import React from 'react';
import { Component } from '@poa/core';
class HomePage extends React.Component {
t; // injected by Poa
store; // injected by Poa
actions; // injected by Poa
handleClick = () => {
this.actions.dunnoAction(true);
};
render() {
return (
{this.t('helloMessage')}
{this.store.dunnoState ? 'Poa!' : null}
Do jumbo!
);
}
}
export default Component({ namespaces: ['homeScreen'] })(HomePage);
```
Notice that `store` and `actions` are injected gently by Poa.
And the last step, update our boot configuration!
```js
import { boot } from '@poa/core';
import { routes } from './routes';
import { en } from './locales/en';
import { initialState } from './store/hello.state';
import * as actions from './store/hello.actions';
boot({
// routing configuration
router: { routes },
// localization configuration
i18n: {
lng: 'en',
resources: { en }
},
// state managment configuration
state: {
initial: initialState,
actions: actions
}
});
}
```
Now, when you click on "Do jumbo!" it should dispatch the action, than this action will go throught mutator and after that, side affects are triggered. After that your component will re-render automatically!
In Poa we use custom version of satcheljs. But for core principles you can check (https://github.com/Microsoft/satcheljs)[https://github.com/Microsoft/satcheljs]
// TODO: describe Poa internal state management
### DI
You can pass additional `env` can, and it will be injected to your components and side effects
```js
// src/index.js
import { boot } from '@poa/core';
import { routes } from './routes';
import { en } from './locales/en';
import { initialState } from './store/hello.state';
import * as actions from './store/hello.actions';
boot({
router: { routes },
i18n: {
lng: 'en',
resources: { en }
},
state: {
initial: initialState,
actions: actions
},
// environment confugiration
env: {
http: fetch.bind(window)
}
});
}
```
So now, you can do the following
```js
// src/stores/hello.actions.js
import { createAction, addMutator, addSideEffects } from '@poa/state';
export const dunnoAction = createAction('dunno', newValue => ({ newValue }));
addMutator(dunnoAction, (payload, { store }) => {
store.dunnoState = payload.newValue;
});
addSideEffects(dunnoAction, async (payload, { store, env }) => {
// here is your injected env!
await env.http('/users');
});
```
### Notice on actions injection in addSideEffects
If you need to invoke another actions from sideEffects (you definetly need it), they are injected!
```js
// src/stores/hello.actions.js
import { createAction, addMutator, addSideEffects } from '@poa/state';
export const dunnoAction = createAction('dunno', newValue => ({ newValue }));
export const dunnoActionSuccess = createAction('dunnoSuccess', () => ({}));
addMutator(dunnoAction, (payload, { store }) => {
store.dunnoState = payload.newValue;
});
addSideEffects(dunnoAction, async (payload, { store, env, actions }) => {
await env.http('/users');
// here is your actions!
actions.dunnoActionSuccess();
});
```
This is needed, when you need to access your actions from another module to avoid circular imports.
### Notice on async actions
To avoid doing like
```js
addSideEffects(dunnoAction, async (payload, { store, env, actions }) => {
try {
// start action sets isLoading=true
actions.dunnoActionStart();
// fetch data
await env.http('/users');
// success action sets isLoadgin=false
actions.dunnoActionSuccess();
} catch (e) {
// failed action isLoadgin=false isError=true
actions.dunnoActionFailed();
}
});
```
You can `await` on action! We make sure that all side affects are resolved.
```js
...
async handleClick() {
this.setState({ isLoading: true });
this.actions.dunnoAction();
this.setState({ isLoading: false });
}
...
```
### Documentation website
Under construction.
### Tech used that to make it possible
Runtime:
* react
* react-dom
* mobx
* mobx-react
* mobx-little-router
* mobx-little-router-react
* satcheljs
* i18next
Build:
* lerna
* microbundle
* parcel
Code:
* prettier
### TODO
* [ ] i18next .use()
* [ ] export all mobx stuff
* [ ] HTTP Client
Future:
* [ ] CLI for project setup / create boilerplate code
* [ ] Isomorphic support
* [ ] React Native support
```
```