Gian Marco Toso
Drinking coffee and saving the world. Software Engineer and professional geek
or: how to stay sane when developing medium to large applications and not be terrified of having to implement new features
Gian Marco Toso
@gianmarcotoso
gianmarcotoso
gianmarcotoso.com
polarityb.it
Software Engineer, Nice Guy
Code Reusability
Better work distribution among teammates
Separation of Concern
Presentation Layer
Data Layer
Modules
Application Structure
Store
Presentation
Action
Reducer
Present
How does it work?
As the name suggests, this layers should provide some sort of visual representation of the data it's consuming
Interact
Most applications require interaction from the user. The presentation layer should expose some sort of interaction mechanism allowing the user to perform actions on what's presented
Fetch Data
What does it do?
From a server, a local data store or any other source, either synchronously or asynchronously, and store it in its own state
Provide Data
Have a publicly consumable surface which allows an external entity to consume the data in the store, either raw or reformatted for a specific purpose
Manipulate Data
Have a publicly consumable surface which allows an external entity to manipulate the data in the store, and save it either locally or on an external store such as a server or a local database
+
+ a 1000 other modules...
=
An application stack!
ReactJS and Redux work together by connecting components
import React from 'react'
import { connect } from 'react-redux'
class MyComponent extends React.Component {
/* ... */
}
const select = state => { /* ... selector code ... */ }
export default connect(select)(MyComponent)
(thanks to the `react-redux` library)
"A module...
module/
components/
actions.js
actionTypes.js
constants.js
index.js
model.js
reducer.js
selectors.js
// module/index.js
import * as actions from './actions';
import * as components from './components';
import * as constants from './constants';
import reducer from './reducer';
import * as selectors from './selectors';
export default {
actions,
components,
constants,
reducer,
selectors
};
A module is a independent unit of an application
A module can define a presentation layer
A module can define a data layer
A module can depend on other modules
A module should depend on other modules as little as possible
Presentation Module
Presentation Module
Presentation Module
Presentation Module
Data Provider
Data Provider
Data Provider
Data Source
Data Source
Data Source
Data Source
A presentation module is used to define a feature of the presentation layer and can contain:
Components
Routes
Module/
- Components/
- MyComponent/
- MyComponent.jsx
- MyComponent.spec.jsx
- MyComponent.css
- index.js
- Routes.jsx
- index.js /* exports public API! */
A Reducer, Actions and Action Creators *
* If they need to have something on the application state that is not part of the data layer, such as the state of a form, a filter or something else related to the UI
A data source is used to define a feature of the data layer and can contain:
A Reducer
Actions
DataSource/
- ActionCreators.js
- Actions.js
- DefaultState.js
- Reducer.js
- index.js /* exports public API! */
Action Creators
A Default State
A Data Provider is an Higher Order Component that allows for a Presentation Module to consume a Data Source. As its name states, a Data Provider provides data. It doesn't even have to provide data from a single data source, it can provide it from multiple ones!
import { createStructuredSelector } from 'reselect'
import { connect } from 'react-redux'
import * as ActionCreators from 'modules/sources/Posts/ActionCreators'
// Suppose there is an addPost() action creator
let postsSelector = state => state.posts.all
let select = createStructuredSelector({
posts: postsSelector
})
export default connect(select, ActionCreators)
import React from 'react'
import WithPosts from 'providers/Posts'
class PostList extends React.Component {
handleAddPost() {
this.props.addPost({
title: 'New Post',
date: new Date()
})
}
render() {
return (
<div>
<ul>
{this.props.posts.map(post => (
<li>{post.title}</li>
))}
</ul>
<button
onClick={this.handleAddPost.bind(this)}
>Do Stuff</button>
</div>
)
}
}
export default WithPosts(PostList)
Presentation Module
Presentation Module
Presentation Module
Presentation Module
Data Provider
Data Provider
Data Provider
Data Source
Data Source
Data Source
Data Source
Structuring your application well goes a long way when you need to know where to look for a specific piece, or when you need to add or even remove something.
An application is not made only by modules, it also has other things like services, utilities, styles, dumb components, configuration files, you name it!
Tips and tricks
Have a folder for each different kind of "element"
- src
- bootstrap/
- components/
- config/
- core/
- data/
- modules/
- providers/
- services/
- utils/
index.js
Tips and tricks
Place each component in its own folder, with an index.js with a default export to make importing easy!
- AwesomeComponent
- AwesomeComponent.jsx
- AwesomeComponent.spec.jsx
- AwesomeComponent.css
- index.js
...and don't forget to include tests!
Tips and tricks
You can find a boilerplate application that follows the guidelines of this presentation at
I hope you enjoyed this!
By Gian Marco Toso
Slides for my talk at the 2016 ReactJS Day in Verona
Drinking coffee and saving the world. Software Engineer and professional geek