React & AltJS — Basic Guidelines and Best Practises

Murtaza Zaidi
Jul 10, 2017 · 4 min read

Prerequisites: Basic understanding of React, AltJS and Flux architecture

Flux Architecture

Pages

Page is just a component, it serves as the entry points from each Route. Pages normally render only the Container Components but can also render other Pages (following example bellow). Pages also:

  • Get URL parameters and pass them down as props.
  • Setup context to pass down as props.
  • Render on part of the screen a component that must be shown to all other children pages on same route.
class MyDashboardPage extends Component {static propTypes = {
children: PropTypes.node,
params: PropTypes.object,
};
componentDidMount() {
document.title = 'Dashboard';
}
render() {
const {
children,
params,
} = this.props;
if (children) {
// renders child on dashboard route
// for e.g. /dashboard/reporting will render
// ReportingPage
return React.cloneElement(children, params);
}
// render MyDashboardContainer
return (
<MyDashboardContainer
params={params.shouldScroll}
/>
);
}
}

Container Components

A Container is a component close to the top of the nested hierarchy that listens for events that are broadcasted by the Stores. It provides the glue code to get the data from the stores and to pass this data down as props on the chain of its descendants. Having one of these controllers governing any significant section of the page can uncouple data handle code from the data representation components.

The duty of the container component is:

  • handle all the data fetching and communication with the stores, it then passes it down as props to its children;
  • handle business logic
  • trigger actions and manages its state
  • DON’T call source directly, use an action instead

To bind stores, use AltJSAltContainer component or connectToStore Higher Order Component.

AltContainer Example

class MyFinanceContainer extends Component {

// only fetch for data when already mounted
componentDidMount() {
CreditCardActions.fetchCreditCardDetails();
BankActions.fetchBankDetails();
}

render() {
const {
bankId,
cardId,
} = this.props;

return (
<AltContainer
stores={{
creditCards: () => ({
store: CreditCardStore,
value: CreditCardStore.getCardById(cardId),
}),
banks: () => ({
store: BankStore,
value: BankStore.getBankById(bankId),
}),
}}
>
<MyFinanceSection />
</AltContainer>
);
}
}

connectToStores Example:

class UserProfileContainer extends Component {static getStores() {
return [UserStore];
}
static getPropsFromStores() {
const {
user,
loading,
} = UserStore.getState();
return { user, loading };
}
render() {
const {
user,
loading,
} = this.props;
return (
<div>
<UserProfileSection user={user} />
<PageLoader loading={loading} />
</div>
);
}
}

Presentational Components

These components are children of Container Components and receive all the data from the containers and just present it without any additional processing. There is no business logic associated with these components are they are preferred to be stateless functional components i.e. they do not maintain any state of their own and re-render only when props coming from parent changes.

DO

  • render data received as props
  • handle user interactions through callback events
  • must be pure functions/components
  • prefer stateless functional components
  • prefer flat props over objects in props
  • eventually, a component that nests a few other together can have suffix of Section with its name

DON’T

  • access Source or Actions
  • set components on state (e.g render a list of component and set to the state)
  • handle business logic
  • render dynamic array assigning the array index as the item key attribute, use an ID instead (not applicable on React 15+)
  • generate IDs for item keys on render (not applicable on React 15+)
  • assign props to state
  • use .bind, use fat arrow ( => )instead for performant and clean code
  • duplicate state between Parent and Child components

Stores

They can be considered as simple key-value stores for application state. Any change in Stores re-renders the components listening to store for some value. There can be multiple stores for multiple domains or types of data which constitute application state.

DO

  • hold data only related to the application state in stores
  • store normalized data (parsed as per component interfaces) from APIs
  • splits stores into domains (such as User, CreditCard, Bank)
  • provide static getter methods
  • clear state after logout (when it applies)
  • get payload from the dispatcher and initialize Immutable Map/List/Set etc if needed

DON’T

  • handle component logic into stores
  • handle user interaction logic (such as the selected item or current item been shown, keep it in component state)
  • duplicate state into many stores, keep a single source of Truth
  • store components references. You can go to jail for this.
  • have direct setter methods, only change state from dispatcher events
  • handle UI logic (such as defining class name)
  • update store with setTimeout, all store changes must come from a dispatcher

Actions

It’s a Javascript object that describes what we want to do, and the data we need to do it. Stores listen to different actions who sometime call source/API or sometime dispatch with container generated data. This dispatched action and data can then be listened by multiple stores which change their state accordingly.

DO

  • maps application actions
  • dispatch events to stores
  • consume sources
  • use generateActions for view actions (follow example below)

DON’T

  • handle business logic
  • change routes, do it in the Container
  • use .defer or setTimeout

Murtaza Zaidi

Written by

Developer, Trouble maker @VentureDive; Curiosity & Thrill

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade