1. Refactor Update Dialog
In this step we'll be refactoring the UpdateTweetDialog to leverage the blueprint we just created.
You can view the finished code for this step by checking out the update.1
branch of the completed project.
Dialog Comparison
If you compared the original create dialog with the update dialog, very little is different. In fact, the only code that's different is reflected below:
...
propTypes: {
tweet: PropTypes.object.isRequired
},
getInitialState() {
const { tweet } = this.props;
return {
data: {
text: tweet.data.text,
userId: tweet.data.userId
}
};
},
request(data) {
const { tweet } = this.props;
lore.actions.tweet.update(tweet, data);
},
render() {
...
return (
<div className="modal-dialog">
...
<h4 className="modal-title">
Update Tweet
</h4>
...
<div className="modal-footer">
...
<button
type="button"
className="btn btn-primary"
disabled={hasError}
onClick={this.onSubmit}
>
Update
</button>
...
</div>
...
</div>
);
}
..
In this case, the update dialog is intended to update a tweet, and so it requires a prop which is the tweet that should be updated.
The getInitialState()
method then uses that tweet
to set the initial state of the form, and when the form is submitted, the request()
method uses the update
action instead of the create
action.
Additionally, (looking at the render()
method) the title of the form is "Update Tweet" instead of "Create Tweet", and the onSubmit
button says "Update" instead of "Create".
Other than that, the forms are identical.
Refactor Update Dialog
Lucky for us, it turns out that none of the differences captured above affect the blueprint, which means we can reuse it for the update dialog.
Open the update dialog located at src/dialogs/tweet/update/index.js
and replace the contents with the code shown below:
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import OptimisticBlueprint from '../../_blueprints/Optimistic';
export default createReactClass({
displayName: 'UpdateTweetDialog',
propTypes: {
onCancel: PropTypes.func,
tweet: PropTypes.object.isRequired
},
getInitialState() {
const { tweet } = this.props;
return {
data: {
text: tweet.data.text,
userId: tweet.data.userId
}
};
},
request(data) {
const { tweet } = this.props;
lore.actions.tweet.update(tweet, data);
},
render() {
const { data } = this.state;
const { schema, fieldMap, actionMap } = lore.config.dialogs;
return (
<OptimisticBlueprint
title="Update Tweet"
onCancel={this.props.onCancel}
data={data}
schema={schema}
fieldMap={fieldMap}
actionMap={actionMap}
request={this.request}
validators={function(data) {
return {
text: [function(value) {
if (!value) {
return 'This field is required';
}
}],
userId: [function(value) {
if (value === undefined) {
return 'This field is required'
}
}]
};
}}
fields={[
{
key: 'text',
type: 'text',
props: {
label: 'Message',
placeholder: "What's happening?"
}
},
{
key: 'userId',
type: 'select',
props: {
label: 'User',
options: function(getState) {
return getState('user.find');
},
optionLabel: 'nickname'
}
}
]}
actions={[
{
key: 'cancel',
type: 'default',
props: (form) => {
return {
label: 'Cancel',
onClick: form.callbacks.dismiss
};
}
},
{
key: 'submit',
type: 'primary',
props: (form) => {
return {
label: 'Update',
disabled: form.hasError,
onClick: form.callbacks.onSubmit
};
}
}
]}
/>
);
}
});
While we won't do in this tutorial, if you compare the create and update dialogs at this point, you'll notice the validators
and fields
are identical. And if you wanted, you could even move that part of the code into a location both dialogs could share, to further reduce code.
Visual Check-in
If everything went well, clicking the edit link will still launch a dialog that you can use to edit an existing tweet.

Code Changes
Below is a list of files modified during this step.
src/dialogs/tweet/update/index.js
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import OptimisticBlueprint from '../../_blueprints/Optimistic';
export default createReactClass({
displayName: 'UpdateTweetDialog',
propTypes: {
onCancel: PropTypes.func,
tweet: PropTypes.object.isRequired
},
getInitialState() {
const { tweet } = this.props;
return {
data: {
text: tweet.data.text,
userId: tweet.data.userId
}
};
},
request(data) {
const { tweet } = this.props;
lore.actions.tweet.update(tweet, data);
},
render() {
const { data } = this.state;
const { schema, fieldMap, actionMap } = lore.config.dialogs;
return (
<OptimisticBlueprint
title="Update Tweet"
onCancel={this.props.onCancel}
data={data}
schema={schema}
fieldMap={fieldMap}
actionMap={actionMap}
request={this.request}
validators={function(data) {
return {
text: [function(value) {
if (!value) {
return 'This field is required';
}
}],
userId: [function(value) {
if (value === undefined) {
return 'This field is required'
}
}]
};
}}
fields={[
{
key: 'text',
type: 'text',
props: {
label: 'Message',
placeholder: "What's happening?"
}
},
{
key: 'userId',
type: 'select',
props: {
label: 'User',
options: function(getState) {
return getState('user.find');
},
optionLabel: 'nickname'
}
}
]}
actions={[
{
key: 'cancel',
type: 'default',
props: (form) => {
return {
label: 'Cancel',
onClick: form.callbacks.dismiss
};
}
},
{
key: 'submit',
type: 'primary',
props: (form) => {
return {
label: 'Update',
disabled: form.hasError,
onClick: form.callbacks.onSubmit
};
}
}
]}
/>
);
}
});
Next Steps
Next we're going to refactor the delete dialog.