Skip to content

Instantly share code, notes, and snippets.

@davelnewton
Last active November 29, 2016 15:50
Show Gist options
  • Save davelnewton/5104aa8f2fd641ee1d26ddba190656fa to your computer and use it in GitHub Desktop.
Save davelnewton/5104aa8f2fd641ee1d26ddba190656fa to your computer and use it in GitHub Desktop.
Misc React Refactors

Trivial refactoring of the render method

The length of the render function makes it difficult to know what all it's responsible for.

I broke out the wrapper <div> into a small component, and the AgGrid row into a separate component.

Moving handlers etc.

I don't know how Flux works, but I'd make each of the user controls their own components. They can update the store as they do now (roughly, depending on how Flux does things like this) with results/etc still handled by the containing component.

onUserDetailChanged

I flattened this out to avoid deep nesting, which makes things difficult to think about. Since none of the conditions depend on each other, and everything is short, this was easy, and early returns are easy to reason about.

I moved the FeedbackMessage processing into a switch statement. This is a stylistic choice, but IMO they're easier to update when you add additional feedback messages. This should be moved into a separate function, though, which makes testing even easier.

If I were doing this in real life I'd probably still whittle this down to a set of states encompassing the feedback messages, data errors, and success. I'd move it either into a switch statement, or a map of states => methods, or whatever.

render: function () {
const { entity, gridOptions, userPermissionsColumns, userPermissions } = this.state
, { langDict } = LanguageLoader
return (
<div>
<h1>{LanguageLoader.langDict.lblUserDetail}</h1>
<form>
<FormRow>
<label htmlFor="userUsername">{langDict.lblUsername}</label>
<input
type="text"
className="form-control"
id="userUsername"
value={entity.Username}
placeholder={langDict.lblUsername}
onChange={this.onUsernameChanged}
/>
</FormRow
<FormRow>
<label htmlFor="userEmail">{langDict.lblEmailAddress}</label>
<input
type="text"
className="form-control"
id="userEmail"
value={entity.Email}
placeholder={langDict.lblEmail}
onChange={this.onEmailChanged}
/>
</FormRow>
</form>
<GridRow
label={langDict.lblPermissionsFromRole}
gridOptions={gridOptions}
permCols={userPermissionsColumns}
perms={userPermissions}
/>
);
}
const FormRow = ({ children }) =>
<div className="row">
<div className="col-lg-3 col-md-4 col-sm-6 col-xs-9 col-centered">
<div className="form-group">
{children}
</div>
</div>
</div>
const GridRow = ({ label, gridOptions, permCols, perms }) =>
<div className={userPermissions === null ? 'hidden' : ''}>
<FormRow>
<label>{label}</label>
<div style={{height: 400}} className="ag-fresh">
<AgGridReact
gridOptions={gridOptions}
columnDefs={userPermissionsColumns}
rowData={userPermissions}
/>
</div>
</FormRow>
</div>
onUserDetailChanged: function() {
var data = AdminUserDetailStore.getData();
GuiHelper.blockGuiLoading(false);
if (typeof data.FeedbackMessage !== 'undefined') {
switch (data.FeedbackMessage) {
case ActionConstants.ERROR:
GuiHelper.unexpectedError();
break;
case ActionConstants.SUCCESS:
GuiHelper.infoDialog(BootstrapDialog.TYPE_SUCCESS, LanguageLoader.langDict.msgUserSaved);
break;
}
return;
}
if (!_.isEmpty(dataErrors)) {
GuiHelper.infoDialog(BootstrapDialog.TYPE_DANGER, GuiHelper.renderErrors(data.Errors));
return;
}
this.setState({ entity: data.Data });
// Load the user permissions if required
// (CAN I PLACE THIS CODE ELSEWHERE THAN IN THIS FUNCTION?)
var userPermissions = AdminUserDetailPermissionsStore.getData().Data;
if (this.state.entity.Id !== 0 && typeof userPermissions === 'undefined') {
this.loadUserPermissions(data.Data.Username);
}
},
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment