Codementor Events

React + Redux — Best Practices

Published May 16, 2018Last updated Aug 31, 2019

Originally published in medium.com/js-imaginea.

This article mainly focuses on implementing some good practices I follow when building large scale applications with React and Redux.

Differentiate Presentational Components and Container Components.

When we are architecting a react application with redux, we should split our components into presentational and container components.

Presentational components are components that render HTML. All our presentational components are stateless components, so are written as functional stateless components unless they need state and lifecycle hooks. Presentational components will not interact with redux store for state. They receive data via props and render it.

Container components are for getting data from redux store and providing the data to the presentational components. They tend to be stateful.

Presentational Component should be stateless functional component as shown:

// LoggedinUsername.js
 
export const LoggedinUsername = ({ username }) => (
  <div>Logged in user:{username}</div>
);

Container Component should be stateful functional component until unless you are forced to use React component life cycle methods.

// LoginSection.js

import React from 'react';
import { connect } from 'react-redux';
import {LoggedinUsername} from './LoggedinUsername';

const LoginSection = ({ username }) =>(
<div>
 <LoggedinUsername username={username}/>
</div>);

const mapStateToProps = state => ({
username:state.username,
});

export const LoginSectionContainer = connect(mapStateToProps)(LoginSection);

Points to be noted:

  • We can see improved performance when using stateless functional components.These components avoid unnecessary checks and memory allocations and are therefore more performant.
  • It will be easy to test a component , if you write the component as simple as possible by splitting presentational components and container components.

Use bindActionCreators for dispatching actions

Redux’s event dispatching system is the heart of its state management functionality. However, it can be tedious to pass down the dispatch function as a prop to every component that needs to dispatch an action.

Avoid this.

// Container.js
  ...
  render() {
    return (
      <CustomButton
        itemId={this.props.selectedItem.Id}
        dispatch={this.props.dispatch}
      />
    );
  }
 
// CustomButton.js
 
import { customItems } from '../actions/itemActions';
 
const CustomButton = ({ itemId, dispatch, active }) =>
  <button
    className={`button ${active ? 'active' : 'inactive'}`}
    onClick={() => dispatch(customItems(itemId))}
  />;

Avoid this.

const mapDispatchToProps = dispatch => {
  return {
    dispatchCustomersFilter: customers => {
      dispatch(filterDataByCustomers(customers));
    },
 
    dispatchSkillsFilter: skills => {
      dispatch(filterDataBySkills(skills));
    }
  };
};
 
export const TableView = connect(mapStateToProps, mapDispatchToProps)(
  _TableView
);

Instead do this.

const mapDispatchToProps = dispatch =>
  bindActionCreators({ filterTalentPoolDataBySkills }, dispatch);
 
export const TalentTableView = connect(mapStateToProps, mapDispatchToProps)(
  _TalentTableView
);

In the above code filterTalentPoolDataBySkills in bindActionCreators is available as this.props.filterTalentPoolDataBySkills to dispatch your action. It will make it easier to maintain the code for long run.

Try to avoid using setState and component lifecycle hooks when using Redux:

Manage the application state using redux store when it is global state. Try to avoid using setState in your component when you are using state management libraries like redux. Use component state when it makes sense ie. A Button component that shows a tooltip when hovered would not use Redux.

Avoid Doing this.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import '../../../components/table/TableView.css';
 
export class _TalentTableView extends Component {
  constructor(props) {
    super(props);
    this.state = {
      talentPool: []
    };
  }
 
  componentWillReceiveProps(nextProps) {
    const data = nextProps.talentPools.filter(value => value.level == 'M1');
    this.setState({
      talentPool: data
    })
  }
 
  render() {
    const { talentPool } = this.state;
    return (
      <div>
        {talentPool}
      </div>
    )
  };
 
  const mapStateToProps = state => {
    return {
      talentPools: state.talentPools
    };
  };
 
  export const TalentTableView = connect(mapStateToProps, null)(
    _TalentTableView
  );

Instead do this.

// TalentTableView.js
 
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { getFilteredDataByLevel } from '../../../utils/filters/index';
import '../../../components/table/TableView.css';
 
export class _TalentTableView extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { filteredData } = this.props;
    return (
      <div>
        {filteredData}
      </div>
    )
  };
 
  const mapStateToProps = state => {
    return {
      talentPools: state.talentPools,
      filteredData: getFilteredDataByLevel(state.talentPools)
    };
  };
 
  export const TalentTableView = connect(mapStateToProps, null)(
    _TalentTableView
  );
// index.js
 
// @flow
import {TalentPoolRecord} from '../models/TalentPoolRecord';
 
export const getFilteredDataByLevel = (talentData:TalentPoolRecord)=>{
   return talentData.filter(value => value.level == 'M1');
}

Here we used the redux store to get state and render it in the view directly. There is no need of using setState and component lifecycle hooks again. Redux is there to do the state management job for you.

Using .bind() in best way:

There are two ways of binding the custom component’s this scope.

  1. Binding them in constructor.
class App extends Component {
  constructor(props) {
    super(props);
    this.updateValue = this.updateValue.bind(this);
  }
updateValue(evt) {
   ...
  }
render() {
    return (
      <form>
        <input onChange={this.updateValue} ... />    
      </form>
    )
  }
}

With this way only one extra function is created at the time of component creation, and that function is used even when render is executed again.

  1. Binding at the time of passing as prop value.
<input onChange={this.updateValue.bind(this)} ... />

.bind() method creates a new function each time it is run, this method would lead to a new function being created every time when the render function executes . This has some performance implications. In small applications we cannot notice them, where as in large applications we can notice them. So its not prefferable to bind a function at the time of passing as a prop value.

Solution:

  1. Its better to bind your custom functions in constructor.
  2. There is a Babel plugin called Class properties transform . You can write auto-bound function using the fat-arrow syntax.
class App extends Component {
  constructor(props) {
    super(props);
// No functions to bind
}
updateValue = (evt) => {
   ...
  }
render() {
    return (
      <form>
        <input onChange={this.updateValue} ... />
      </form>
    )
  }
}

If we see the above code there are no functions to bind.

Use Accessor Functions

For better code refactoring move all your functions which do filtering , parsing and other data transformation logics into seperate file and import them to use those functions inside your connect method of react-redux as shown.

// index.js
 
// @flow
import {TalentPoolRecord} from '../models/TalentPoolRecord';
 
export const getFilteredDataByLevel=(talentData:TalentPoolRecord)=>{
 
return talentData.filter(value=>value.level=='M1')
 
}

By doing this it will be easy to add flow types for your functions.

// TalentTableView.js
 
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { SelectFilter } from '../../../components/filters/SelectFilter';
import { getFilteredDataByLevel } from '../../../utils/filters/index';
import '../../../components/table/TableView.css';
 
export class _TalentTableView extends Component {
  constructor(props) {
    super(props);
  }
  render() {
    const { filteredData } = this.props;
    return (
      <div>
        {filteredData}
      </div>
    )
  };
 
  const mapStateToProps = state => {
    return {
      talentPools: state.talentPools,
      filteredData: getFilteredDataByLevel(state.talentPools)
    };
  };
 
  export const TalentTableView = connect(mapStateToProps, null)(
    _TalentTableView
  );

Write cleaner code using ES6 Features

Writing cleaner code will make the developers life easy to understand and maintain the code. ES6 features will give us much cleaner way of writing code in React.

Use Destructuring & spread attributes:

Avoid this.

class AutoloadingPostsGrid extends React.Component {
  render() {
    return (
      <div className={this.props.className}>
        <PostsGrid gridVal={this.props.gridVal} userId={this.props.userId} panelNo={this.props.panelNo} />
        <button onClick={this.handleLoadMoreClick}>Load more</button>
      </div>
    );
  }
}

Instead do this.

class AutoloadingPostsGrid extends React.Component {
  render() {
    const {
      className,
      ...others  // contains all properties of this.props except for className
    } = this.props;
    return (
      <div className={className}>
        <PostsGrid {...others} />
        <button onClick={this.handleLoadMoreClick}>Load more</button>
      </div>
    );
  }
}

Use Arrow functions:

Avoid this:

constructor() {
   super();
   this.renderTodoList.bind(this);
 }

 renderTodoList(arrayOfTodos) {
   var arrayOfComponents = [];
   for (i = 0; i < arrayOfTodos.length; i++) {
     var thisTodo = arrayOfTodos[i];
     arrayOfComponents.push(<Todo key={thisTodo.id} text={thisTodo.text} />);
   }
   return arrayOfComponents;
 }

Instead do this.

renderTodoList = arrayOfTodos =>
    arrayOfTodos.map(todo => <Todo key={todo.id} {...todo} />);

Use Flow Types

One thing is certain that type checking is expected to be the future of JS. Generally many developers have a confusion between what to implement between flow and typescript and how smoothly they can be integrated into a current project.

Typescript is more sophisticated to integrate into current project and flow feels simple to introduce, admitting with a warning that it might be inspecting less of your coding as expected.

As the javascript project grows without typing, the more difficult refactoring will become. The larger the project the higher the risk when refactoring. Using type checking may not completely eliminate risk but it will greatly reduce it.

Benifits in using flow:

  1. On time detection of bugs or errors.
  2. Communicates the purpose of the function.
  3. It Scales Down Complex Error Handling.
  4. Wipes Out Runtime Type Errors.

Use axios library for http requests over jQuery ajax:

Fetch API and axios are the most preferable ways of making http requests. Between those two there are some advantages of using axios library. They are

  • It allows performing transforms on data before request is made or after response is received.
  • It allows you to alter the request or response entirely (headers as well). also perform async operations before request is made or before Promise settles.
  • Built-in XSRF protection.

Use styled-components to style your components

The basic idea of styled-components is to enforce best practices by removing the mapping between styles and components. This way, you can colocate your components with their corresponding styles — resulting in localised class names that do not pollute the global css namespace.

If you decide to use styled-components, do not forget to install plugin to support syntax highlighting in strings or maybe help creating a new one.

Example:

import React from "react";
import styled from "styled-components";
 
const StyledView = styled.View`
  background-color: papayawhip;
`;
 
const StyledText = styled.Text`
  color: palevioletred;
`;
 
class MyReactComponent extends React.Component {
  render() {
    return (
      <StyledView>
        <StyledText>Hello World!</StyledText>
      </StyledView>
    );
  }
}

Test your React components

The goal of unit testing is to segregate each part of the program and test that the individual parts are working correctly. It isolates the smallest piece of testable software from the remainder of the code and determines whether it behaves exactly as you expect. We can find bugs in early stage.

In React to test component we use Jest and Enzyme. Jest was created by Facebook and is a testing framework to test javascript and React code. Together with Airbnb’s Enzyme, which is a testing utility, makes it the perfect match to easily test your React application.

Use ES Lint for better coding conventions.

Well run projects have clear consistent coding conventions, with automated enforcement. Besides checking style, linters are also excellent tools for finding certain classes of bugs, such as those related to variable scope. Assignment to undeclared variables and use of undefined variables are examples of errors that are detectable at lint time.

For React specific linting rules go with esint-plugin-react  .

For linting flow types rules go with eslint-plugin-flowtype and eslint-plugin-flowtype-errors .

Follow me:
Twitter: https://twitter.com/iravitejakumar
GitHub: https://github.com/iravitejakumar

Discover and read more posts from Ravi Teja Kumar Isetty
get started
post commentsBe the first to share your opinion
Show more replies