If you've got any questions about upgrading you can ask the team in Marty's Gitter chatroom.
Singleton to Application
Firstly, if you're using ES6 you will need to remove all references to Marty.register(...) and just return the original type.
// Instead of
export default Marty.register(UserStore);
// You just export the type
export default UserStore;var Application = Marty.createApplication(function () {
this.register('userStore', require('./stores/userStore'));
...
});
module.exports = Application;class Application extends Marty.Application {
constructor(options) {
super(options);
this.register('userStore', require('./stores/userStore'));
...
}
}
export default Application;Next, when calling React.render you must wrap the element you are about to render with an ApplicationContainer, passing an instance of your application in via the props.
var app = new Application();
var { ApplicationContainer } = require('marty');
React.render((
<ApplicationContainer app={app}>
<User id={123} />
</ApplicationContainer>
), document.body);Now that we're returning types instead of instances we need to update all references within our application. This largely means that, instead of require'ing your dependency, you must instead call this.app.{dependencyId}. e.g.
// Instead of
var UserAPI = require('../sources/userAPI');
class UserActions extends Marty.ActionCreators {
deleteUser(id) {
UserAPI.for(this).deleteUser(id);
}
}
// Assuming you had registered UserAPI with the id 'userAPI'
class UserActions extends Marty.ActionCreators {
deleteUser(id) {
this.app.userAPI.deleteUser(id);
}
}This is largely the same from with React components. The only requirement is that the component is either wrapped in a container or is using the state mixin. There are times when neither are appropriate so we've introduced the app mixin which simply injects app into your component.
class User extends React.Component {
saveUser() {
this.app.userActionCreators.saveUser(this.props.id);
}
}
export default Marty.createContainer(User);For the listenTo property in containers and state mixins you need to replace type references with their dependency Id's. The listenTo behavior is identical otherwise.
export default Marty.createContainer(User, {
// instead of
listenTo: [
UserStore,
FriendsStore
],
// Use strings
listenTo: [
'userStore',
'friends.store' // To access app.friends.store
],
fetch {
user() {
return this.app.userStore.getUser(123);
}
}
});To update your tests, we recommend you look at our test examples and test utils.
Isomorphism
Contexts have been completely removed and most functions that were previously on Marty, e.g. Marty.replaceState, Marty.clearState, Marty.dehydrate and Marty.rehydrate have been moved to to the application.
// Instead of
var context = Marty.createContext();
Marty.replaceState({ ... }, context);
Marty.clearState(context);
Marty.dehyrdate(context);
Marty.rehydrate({ ... }, context);
// You do
var app = new Application();
app.replaceState({ ... });
app.clearState();
app.dehyrdate();
app.rehydrate({ ... });Marty.renderToString has also been moved to the application and has simpler signature.
// Instead of
var context = Marty.createContext();
var options = {
type: Foo,
timeout: 2000,
context: context,
props: { bar: 'baz' }
};
Marty.renderToString(options).then(res => {
console.log('Rendered html', res.html);
console.log('Diagnostics', res.diagnostics);
});
// You do
var app = new Application();
app.renderToString(<Foo bar='baz' />, { timeout: 2000 }).then(res => {
// We've had to split the html body and html state variables out to resolve https://github.com/martyjs/marty/issues/288.
console.log('Rendered html body', res.htmlBody);
console.log('Rendered html state', res.htmlState);
console.log('Diagnostics', res.diagnostics);
});parseJSON
The HttpStateSource internally uses fetch to make HTTP calls for you. If the response contains JSON you need to call res.json() to get the actual JSON. We thought we'd be helpful and do this for you automatically, assigning the JSON to res.body. Unfortunately we did this before we knew fetch was also going to use the body property for other purposes which has caused issues. We therefore need to depreciate this feature. For v0.10 you will get warnings and in v0.11 we will turn feature off by default.
To get rid of the warnings you first need to remove the HTTP hook
require('marty').HttpStateSource.removeHook('parseJSON');Next you will need to update all references to res.body. We recommend putting all of this logic in your HTTP state source
class UserAPI extends Marty.HttpStateSource {
getUser(id) {
return this.get(`/users/${id}`).then(res => {
if (res.ok) {
return res.json();
}
throw new Error('Failed to get user');
});
}
}State mixin's
We warned when we released v0.9 we would be depreciating the state mixin. We've decided to keep them around for v0.10 however we've removed the ability to create a state mixin by passing in a store or by passing in an object hash of stores.
// No longer possible
Marty.createStateMixin(UserStore)
Marty.createStateMixin({
users: UserStore,
friends: FriendsStore
});Rollbacks
Rollbacks are no longer supported. We recommend you look at our suggested approach to handling errors.
Other Depreciations
- You no longer need to declare Id's or displayName's on the type. An instances Id will be populated from from
Application#register(id, type). Marty.registryno longer exists. If you want to get all instances of a given type you can callApplication#getAll(type)require('marty').Dispatcheris no longer supported. Create an application and access the dispatcher.require('marty/http/hooks')is no longer supported. Userequire('marty').hooksinsteadrequire('marty/environment')is no longer supported. Userequire('marty').environmentrequire('marty/fetch')is no longer supported. Userequire('marty').fetchrequire('marty/when')is no longer supported. Userequire('marty').whenrequire('marty/autoDispatch')is no longer supported. Userequire('marty').autoDispatchrequire('marty').Diagnosticsis no longer supported. Userequire('marty').diagnostics