• 18-19 College Green, Dublin 2
  • 01 685 9088
  • info@cunninghamwebsolutions.com
  • cunninghamwebsolutions
    Cunningham Web Solutions
    • Home
    • About Us
    • Our Services
      • Web Design
      • Digital Marketing
      • SEO Services
      • E-commerce Websites
      • Website Redevelopment
      • Social Media Services
    • Digital Marketing
      • Adwords
      • Social Media Services
      • Email Marketing
      • Display Advertising
      • Remarketing
    • Portfolio
    • FAQ’s
    • Blog
    • Contact Us
    MENU CLOSE back  

    Creating Sortable Tables With React

    You are here:
    1. Home
    2. Web Design
    3. Creating Sortable Tables With React
    Thumbnail for 24664
    Smashing Editorial

    Creating Sortable Tables With React

    Creating Sortable Tables With React

    Kristofer Giltvedt Selbekk

    2020-03-20T12:30:00+00:00
    2020-03-21T12:35:57+00:00

    Table sorting has always been a pretty hard issue to get right. There’s a lot of interactions to keep track of, extensive DOM mutations to do and even intricate sorting algorithms, too. It’s just one of those challenges that are hard to get right. Right?

    Instead of pulling in external libraries, let’s try to make stuff ourselves. In this article, we’re going to create a reusable way to sort your tabular data in React. We’ll go through each step in detail, and learn a bunch of useful techniques along the way.

    We won’t go through basic React or JavaScript syntax, but you don’t have to be an expert in React to follow along.

    Creating A Table With React

    First, let’s create a sample table component. It’ll accept an array of products, and output a very basic table, listing out a row per product.

    function ProductTable(props) {
      const { products } = props;
      return (
        <table>
          <caption>Our products</caption>
          <thead>
            <tr>
              <th>Name</th>
              <th>Price</th>
              <th>In Stock</th>
            </tr>
          </thead>
          <tbody>
            {products.map(product => (
              <tr key={product.id}>
                <td>{product.name}</td>
                <td>{product.price}</td>
                <td>{product.stock}</td>
              </tr>
            ))}
          </tbody>
        </table>
      );
    }

    Here, we accept an array of products and loop them out into our table. It’s static and not sortable at the moment, but that’s fine for now.

    Sorting The Data

    If you’d believe all the whiteboard interviewers, you’d think software development was almost all sorting algorithms. Luckily, we won’t be looking into a quick sort or bubble sort here.

    Sorting data in JavaScript is pretty straightforward, thanks to the built-in array function sort(). It’ll sort arrays of numbers and strings without an extra argument:

    const array = ['mozzarella', 'gouda', 'cheddar'];
    array.sort();
    console.log(array); // ['cheddar', 'gouda', 'mozzarella']

    If you want something a bit more clever, you can pass it a sorting function. This function is given two items in the list as arguments, and will place one in front of the other based on what you decide.

    Let’s start by sorting the data we get alphabetically by name.

    function ProductTable(props) {
      const { products } = props;
      let sortedProducts = [...products];
      sortedProducts.sort((a, b) => {
        if (a.name < b.name) {
          return -1;
        }
        if (a.name > b.name) {
          return 1;
        }
        return 0;
      });
      return (
        <Table>
          {/* as before */}
        </Table>
      );
    }

    So what’s going on here? First, we create a copy of the products prop, which we can alter and change as we please. We need to do this because the Array.prototype.sort function alters the original array instead of returning a new sorted copy.

    Next, we call sortedProducts.sort, and pass it a sorting function. We check if the name property of the first argument a is before the second argument b, and if so, return a negative value. This indicates that a should come before b in the list. If the first argument’s name is after the second argument’s name, we return a positive number, indicating that we should place b before a. If the two are equal (i.e. both have the same name), we return 0 to preserve the order.

    Making Our Table Sortable

    So now we can make sure the table is sorted by name — but how can we change the sorting order ourselves?

    To change what field we sort by, we need to remember the currently sorted field. We’ll do that with the useState hook.

    A hook is a special kind of function that lets us “hook” into some of React’s core functionality, like managing state and triggering side effects. This particular hook lets us maintain a piece of internal state in our component, and change it if we want to. This is what we’ll add:

    const [sortedField, setSortedField] = React.useState(null);

    We start by not sorting anything at all. Next, let’s alter the table headings to include a way to change what field we want to sort by.

    const ProductsTable = (props) => {
      const { products } = props;
      const [sortedField, setSortedField] = React.useState(null);
      return (
        <table>
          <thead>
            <tr>
              <th>
                <button type="button" onClick={() => setSortedField('name')}>
                  Name
                </button>
              </th>
              <th>
                <button type="button" onClick={() => setSortedField('price')}>
                  Price
                </button>
              </th>
              <th>
                <button type="button" onClick={() => setSortedField('stock')}>
                  In Stock
                </button>
              </th>
            </tr>
          </thead>
          {/* As before */}
        </table>
      );
    };

    Now, whenever we click a table heading, we update the field we want to sort by. Neat-o!

    We’re not doing any actual sorting yet though, so let’s fix that. Remember the sorting algorithm from before? Here it is, just slightly altered to work with any of our field names.

    const ProductsTable = (props) => {
      const { products } = props;
      const [sortedField, setSortedField] = React.useState(null);
      let sortedProducts = [...products];
      if (sortedField !== null) {
        sortedProducts.sort((a, b) => {
          if (a[sortedField] < b[sortedField]) {
            return -1;
          }
          if (a[sortedField] > b[sortedField]) {
            return 1;
          }
          return 0;
        });
      }
      return (
        <table>

    We first make sure we’ve chosen a field to sort by, and if so, we sort the products by that field.

    Ascending vs Descending

    The next feature we want to see is a way to switch between ascending and descending order. We’ll switch between ascending and descending order by clicking the table heading one more time.

    To implement this, we’ll need to introduce a second piece of state — the sort order. We’ll refactor our current sortedField state variable to keep both the field name and its direction. Instead of containing a string, this state variable will contain an object with a key (the field name) and a direction. We’ll rename it to sortConfig to be a bit clearer.

    Here’s the new sorting function:

     sortedProducts.sort((a, b) => {
      if (a[sortConfig.key] < b[sortConfig.key]) {
        return sortConfig.direction === 'ascending' ? -1 : 1;
      }
      if (a[sortConfig.key] > b[sortConfig.key]) {
        return sortConfig.direction === 'ascending' ? 1 : -1;
      }
      return 0;
    });

    Now, if the direction is ‘ascending’, we’ll do as we did previously. If it’s not, we’ll do the opposite, giving us descending ordering.

    Next up, we’ll create a new function — requestSort — which will accept the field name, and update the state accordingly.

    const requestSort = key => {
      let direction = 'ascending';
      if (sortConfig.key === key && sortConfig.direction === 'ascending') {
        direction = 'descending';
      }
      setSortConfig({ key, direction });
    }

    We’ll also have to change our click handlers to use this new function!

    return (
      <table>
        <thead>
          <tr>
            <th>
              <button type="button" onClick={() => requestSort('name')}>
                Name
              </button>
            </th>
            <th>
              <button type="button" onClick={() => requestSort('price')}>
                Price
              </button>
            </th>
            <th>
              <button type="button" onClick={() => requestSort('stock')}>
                In Stock
              </button>
            </th>
          </tr>
        </thead>
      {/* as before */}
      </table>
    );

    Now we’re starting to look pretty feature-complete, but there’s still one big thing left to do. We need to make sure that we only sort our data when we need to. Currently, we’re sorting all of our data on every render, which will lead to all sorts of performance issues down the line. Instead, let’s use the built-in useMemo hook to memoize all the slow parts!

    const ProductsTable = (props) => {
      const { products } = props;
      const [sortConfig, setSortConfig] = React.useState(null);
      
      React.useMemo(() => {
        let sortedProducts = [...products];
        if (sortedField !== null) {
          sortedProducts.sort((a, b) => {
            if (a[sortConfig.key] < b[sortConfig.key]) {
              return sortConfig.direction === 'ascending' ? -1 : 1;
            }
            if (a[sortConfig.key] > b[sortConfig.key]) {
              return sortConfig.direction === 'ascending' ? 1 : -1;
            }
            return 0;
          });
        }
        return sortedProducts;
      }, [products, sortConfig]);

    If you haven’t seen it before, useMemo is a way to cache — or memoize — expensive computations. So given the same input, it doesn’t have to sort the products twice if we re-render our component for some reason. Note that we want to trigger a new sort whenever our products change, or the field or direction we sort by changes.

    Wrapping our code in this function will have huge performance implications for our table sorting!

    Making It All Reusable

    One of the best things about hooks is how easy it is to make logic reusable. You’ll probably be sorting all types of tables throughout your application, and having to reimplement the same stuff all over again sounds like a drag.

    React has this feature called custom hooks. They sound fancy, but all they are are regular functions that use other hooks inside of them. Let’s refactor our code to be contained in a custom hook, so we can use it all over the place!

    const useSortableData = (items, config = null) => {
      const [sortConfig, setSortConfig] = React.useState(config);
      
      const sortedItems = React.useMemo(() => {
        let sortableItems = [...items];
        if (sortConfig !== null) {
          sortableItems.sort((a, b) => {
            if (a[sortConfig.key] < b[sortConfig.key]) {
              return sortConfig.direction === 'ascending' ? -1 : 1;
            }
            if (a[sortConfig.key] > b[sortConfig.key]) {
              return sortConfig.direction === 'ascending' ? 1 : -1;
            }
            return 0;
          });
        }
        return sortableItems;
      }, [items, sortConfig]);
    
      const requestSort = key => {
        let direction = 'ascending';
        if (sortConfig && sortConfig.key === key && sortConfig.direction === 'ascending') {
          direction = 'descending';
        }
        setSortConfig({ key, direction });
      }
    
      return { items, requestSort };
    }

    This is pretty much copy and paste from our previous code, with a bit of renaming thrown in. useSortableData accepts the items, and an optional initial sort state. It returns an object with the sorted items, and a function to re-sort the items.

    Our table code now looks like this:

    const ProductsTable = (props) => {
      const { products } = props;
      const { items, requestSort } = useSortableData(products);
      return (
        <table>{/* ... */}</table>
      );
    };

    A Last Touch

    There’s one tiny piece missing — a way to indicate how the table is sorted. In order to indicate that in our design, we need to return the internal state as well — the sortConfig. Let’s return that as well, and use it to generate styles we can apply to our table headings!

    const ProductTable = (props) => {
      const { items, requestSort, sortConfig } = useSortableData(props.products);
      const getClassNamesFor = (name) => {
        if (!sortConfig) {
          return;
        }
        return sortConfig.key === name ? sortConfig.direction : undefined;
      };
      return (
        <table>
          <caption>Products</caption>
          <thead>
            <tr>
              <th>
                <button
                  type="button"
                  onClick={() => requestSort('name')}
                  className={getClassNamesFor('name')}
                >
                  Name
                </button>
              </th>
             {/* … */}
            </tr>
          </thead>
          {/* … */}
        </table>
      );
    };

    And with that, we’re done!

    Wrapping Up

    As it turns out, creating your own table sorting algorithm wasn’t an impossible feat after all. We found a way to model our state, we wrote a generic sorting function, and we wrote a way to update what our sorting preferences are. We made sure everything was performant and refactored it all into a custom hook. Finally, we provided a way to indicate the sort order to the user.

    You can see a demo of the table in this CodeSandbox:

    (ra, yk, il)

    From our sponsors: Creating Sortable Tables With React

    Posted on 21st March 2020Web Design
    FacebookshareTwittertweetGoogle+share

    Related posts

    Archived
    22nd March 2023
    Archived
    18th March 2023
    Archived
    20th January 2023
    Thumbnail for 25788
    Handling Continuous Integration And Delivery With GitHub Actions
    19th October 2020
    Thumbnail for 25778
    A Monthly Update With New Guides And Community Resources
    19th October 2020
    Thumbnail for 25781
    Supercharge Testing React Applications With Wallaby.js
    19th October 2020
    Latest News
    • Archived
      22nd March 2023
    • Archived
      18th March 2023
    • Archived
      20th January 2023
    • 20201019 ML Brief
      19th October 2020
    • Thumbnail for 25788
      Handling Continuous Integration And Delivery With GitHub Actions
      19th October 2020
    • Thumbnail for 25786
      The Future of CX with Larry Ellison
      19th October 2020
    News Categories
    • Digital Marketing
    • Web Design

    Our services

    Website Design
    Website Design

    A website is an important part of any business. Professional website development is an essential element of a successful online business.

    We provide website design services for every type of website imaginable. We supply brochure websites, E-commerce websites, bespoke website design, custom website development and a range of website applications. We love developing websites, come and talk to us about your project and we will tailor make a solution to match your requirements.

    You can contact us by phone, email or send us a request through our online form and we can give you a call back.

    More Information

    Digital Marketing
    Digital Marketing

    Our digital marketeers have years of experience in developing and excuting digital marketing strategies. We can help you promote your business online with the most effective methods to achieve the greatest return for your marketing budget. We offer a full service with includes the following:

    1. Social Media Marketing

    2. Email & Newsletter Advertising

    3. PPC - Pay Per Click

    4. A range of other methods are available

    More Information

    SEO
    SEO Services

    SEO is an essential part of owning an online property. The higher up the search engines that your website appears, the more visitors you will have and therefore the greater the potential for more business and increased profits.

    We offer a range of SEO services and packages. Our packages are very popular due to the expanse of on-page and off-page SEO services that they cover. Contact us to discuss your website and the SEO services that would best suit to increase your websites ranking.

    More Information

    E-commerce
    E-commerce Websites

    E-commerce is a rapidly growing area with sales online increasing year on year. A professional E-commerce store online is essential to increase sales and is a reflection of your business to potential customers. We provide professional E-commerce websites custom built to meet our clients requirements.

    Starting to sell online can be a daunting task and we are here to make that journey as smooth as possible. When you work with Cunningham Web Solutions on your E-commerce website, you will benefit from the experience of our team and every detail from the website design to stock management is carefully planned and designed with you in mind.

    More Information

    Social Media Services
    Social Media Services

    Social Media is becoming an increasingly effective method of marketing online. The opportunities that social media marketing can offer are endless and when managed correctly can bring great benefits to every business.

    Social Media Marketing is a low cost form of advertising that continues to bring a very good ROI for our clients. In conjuction with excellent website development and SEO, social media marketing should be an essential part of every digital marketing strategy.

    We offer Social Media Management packages and we also offer Social Media Training to individuals and to companies. Contact us to find out more.

    More Information

    Cunningham Web Solutions
    © Copyright 2025 | Cunningham Web Solutions
    • Home
    • Our Services
    • FAQ's
    • Account Services
    • Privacy Policy
    • Contact Us