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.ximport { createComponent } from 'frint';
const Root = createComponent({
render() {
return (
<p>Hello World</p>
);
}
});
v1.xNow 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.ximport { createApp } from 'frint';
const App = createApp({
name: 'MyApp',
component: MyComponent
});
v1.xComponents are optional in v1.x:
import { createApp } from 'frint';
const App = createApp({
name: 'MyApp',
providers: [
{
name: 'component',
useValue: MyRootComponent
}
]
});
v0.ximport { PropTypes } from 'frint';
v1.xIn React v0.14:
import { PropTypes } from 'react';
To keep things compatible with React v15+:
import PropTypes from 'prop-types';
v0.ximport { 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.xStores 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.ximport { 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.ximport { 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.ximport { 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.ximport { 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.ximport { 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.ximport { 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');
mapToPropsv0.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.xThe 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);