We are still keeping majority of the API in v0.x
backwards compatible with the new v1.x
.
But using old API would give you deprecated warnings, and they can be eliminated by following the guide below.
Recommended equivalent methods for App
instance, introduced in new API:
v0.x | v1.x |
---|---|
app.getService(name) |
app.get(serviceName) |
app.getFactory(name) |
app.get(factoryName) |
app.getModel(name) |
app.get(modelName) |
app.getStore() |
app.get('store') |
app.getState$() |
app.get('store').getState$() |
app.dispatch(action) |
app.get('store').dispatch(action) |
app.render |
app.get('component') |
app.getWidgets() |
app.getApps$() |
v0.x
import { createComponent } from 'frint';
const Root = createComponent({
render() {
return (
<p>Hello World</p>
);
}
});
v1.x
Now we use React directly:
import React, { Component } from 'react';
class Root extends Component {
render() {
return (
<p>Hello world</p>
);
}
}
Note: Remember that the lifecycle methods in Components need to follow React's API too now:
v0.x - Frint createComponent | v1.x - React Component |
---|---|
beforeMount |
componentWillMount |
afterMount |
componentDidMount |
beforeUnmount |
componentWillUnmount |
v0.x
import { createApp } from 'frint';
const App = createApp({
name: 'MyApp',
component: MyComponent
});
v1.x
Components are optional in v1.x
:
import { createApp } from 'frint';
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'component',
useValue: MyRootComponent
}
]
});
v0.x
import { PropTypes } from 'frint';
v1.x
In React v0.14:
import { PropTypes } from 'react';
To keep things compatible with React v15+:
import PropTypes from 'prop-types';
v0.x
import { createApp, combineReducers } from 'frint';
const rootReducer = combineReducers({
foo: fooReducer,
bar: barReducer
});
const App = createApp({
name: 'MyApp',
reducer: rootReducer,
initialState: {}
});
const app = new App();
const store = app.getStore();
v1.x
Stores are optional in v1.x
:
import { createApp } from 'frint';
import { createStore, combineReducers } from 'frint-store';
const rootReducer = combineReducers({
foo: fooReducer,
bar: barReducer
});
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'store',
useFactory: function ({ app }) {
const Store = createStore({
reducer: rootReducer,
initialState: {},
thunkArgument: { app }, // for async actions
});
return new Store();
},
deps: ['app']
}
]
});
const store = app.get('store');
v0.x
import { createApp, createService } from 'frint';
const FooService = createService({
getAppName() {
return this.app.getName();
}
});
const App = createApp({
name: 'MyApp',
services: {
foo: FooService
}
});
const app = new App();
const foo = app.getService('foo');
v1.x
import { createApp } from 'frint';
// just a regular ES6-compatible class
class FooService {
constructor({ app }) {
this.app = app;
}
getAppName() {
return this.app.getName();
}
}
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'foo',
useClass: FooService,
cascade: true, // if you want Apps to access it
deps: ['app'] // values are made available in constructor argument
}
]
});
const app = new App();
const foo = app.get('foo');
v0.x
import { createApp, createFactory } from 'frint';
const BarFactory = createFactory({
getAppName() {
return this.app.getName();
}
});
const App = createApp({
name: 'MyApp',
factories: {
bar: BarFactory
}
});
const app = new App();
const bar = app.getFactory('bar');
v1.x
import { createApp } from 'frint';
// just a regular ES6-compatible class
class BarFactory {
constructor({ app }) {
this.app = app;
}
getAppName() {
return this.app.getName();
}
}
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'bar',
useClass: BarFactory,
cascade: true, // if you want Apps to access it
scoped: true, // means Apps will get a fresh new scoped instance themselves
deps: ['app']
}
]
});
const app = new App();
const bar = app.get('bar');
v0.x
import { createModel, createApp } from 'frint';
const BazModel = createModel({});
const App = createApp({
name: 'MyApp',
models: {
baz: BazModel
},
modelAttributes: {
baz: {
key: 'value'
}
}
});
const app = new App();
const baz = app.getModel('baz');
v1.x
import { createModel, createApp } from 'frint';
const BazModel = createModel({});
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'baz',
useFactory: function () {
return new BazModel({
key: 'value'
});
},
cascade: true
}
]
});
const app = new App();
const baz = app.get('baz');
mapToProps
v0.x
// ./components/Root.js
import { mapToProps, createComponent } from 'frint';
import { Observable } from 'rxjs';
import { addTodo } from '../actions/todos';
const Root = createComponent({
render() {
// ...
}
});
export default mapToProps({
state(state) => ({
todos: state.todos.records
}),
dispatch: {
handleAddButton: addTodo
},
app(app) {
return {
appName: app.getName()
}
}),
shared(sharedState) => ({
counter: sharedState.SomeOtherAppName[reducerName].someKey
}),
services: {
foo: 'foo'
},
factories: {
bar: 'bar'
},
models: {
baz: 'baz'
},
observe(app) {
return Observable
.interval(1000)
.map(x => ({ interval: x }));
}
})(Root);
v1.x
The usage of mapToProps
can be replaced with observe
, along with a helper function streamProps
for keeping code even shorter:
// ./components/Root.js
import React from 'react';
import { Observable } from 'rxjs';
import { observe, streamProps } from 'frint-react';
import { addTodo } from '../actions/todos';
const Root = React.createClass({
render() {
// ...
}
});
export default observe(function (app) {
// We need to return a single Observable from this function.
// Either manually for greater control, or using `streamProps`:
return streamProps({}) // default props to start with
// state
.set(
app.get('store').getState$(),
state => ({ todos: state.todos.records })
)
// dispatch
.setDispatch({
handleAddButton: addTodo
}, app.get('store'))
// app
.set('appName', app.getName())
// shared state
.set(
app.getAppOnceAvailable$('SomeOtherAppName'),
app => app.get('store').getState$(),
state => ({ counter: state[reducerName].someKey })
)
// services
.set('foo', app.get('foo'))
// factories
.set('bar', app.get('bar'))
// models
.set('baz', app.get('baz'))
// observe
.set(
Observable.interval(1000),
x => ({ interval: x })
)
// return final Observable
.get$();
})(Root);