Alexander Ivlev

TILSeptember 05, 2019by Alexander Ivlev

Redux async actions. Tracking loading and errors with React hooks.

If you use redux and async actions, then you probably had to deal with a situation where you need to monitor the loading and error status of this action. With the advent of hooks, it became possible to conveniently transfer this logic to one block and use it everywhere.


import { useState, useCallback } from 'react';

import { useDispatch } from 'react-redux';



function useAsyncAction(action, dependeces = []) {

  const dispatch = useDispatch();

  const [loading, setLoading] = useState(false);

  const [isError, setIsError] = useState(false);



  const asyncAction = useCallback(

    (...args) => {

      async function callback() {

        setLoading(true);

        try {

          const res = await dispatch(action(...args));

          setIsError(false);

          setLoading(false);

          return res;

        } catch (e) {

          setLoading(false);

          setIsError(true);

          return e;

        }

      }

      callback();

    },

    [action, ...dependeces],

  );



  return [asyncAction, loading, isError];

}

Now you can use this hook in your functional component.


// …

  const [load, loading, isError] = useAsyncAction(() => loadActivityRequest(applicationId), [applicationId]);

// …

  load();

TILJuly 27, 2019by Alexander Ivlev

Request Api Adapter

When developing client applications, it is often necessary to send requests to the server.


// ...

client({ url: "/users.json", method: "GET" }).then(...)



We can make our lives a little easier. A convenient abstraction is apiAdapter


// apiAdapter.js

function getUsers() {

  return { url: "/users.json", method: "GET" };

}



const apiAdapter = createAdapter(client, {}, {

  getUsers,  

})

By defining a request in one place, you can now simply call the adapter method you want.


import apiAdapter from './apiAdapter'



apiAdapter.getUsers().then(...)

It is also a useful option to specify basic settings for all requests, as well as handling errors and successful requests.


const apiAdapter = createAdapter(

  client,

  { withCredentials: true },

  {

    getUsers,  

  },

  successHandler,

  errorHandler, 

)

Github

Live example

TILFebruary 23, 2019by Alexander Ivlev

Recompose withContext and getContext. Simple example

Very often for nested components you need to transfer some props of the parent. For example size. So, we have the Card component. It contains a Button component.


  // App.js

  <Card size="sm">

    {/* ... */}

    <div>

      {/* ... */}

      <Button size="sm" onClick={action}>Action</Button>

    </div>

  </Card>



The size for both components is set by the "size" parameter. In the example above, the parameter passed is indicated for both components. In order not to specify the size for the Button each time, you can use the Context to use the one specified for the Card. If you use recompose, it can be super easy:


  // Card.js

  import { getContext } from 'recompose';

  // ...

  export default withContext(

    { size: PropTypes.oneOf(['sm', 'md', 'lg']) },

    ({ size }) => ({ size }),

  )(Card);



  // App.js

  import Button from './Button';

  // ...

  const EnhancedButton = getContext({ size: PropTypes.oneOf(['sm', 'md', 'lg']) })(Button);

Live example

TILFebruary 20, 2019by Alexander Ivlev

Sort lines in the vim editor

Often when writing code, you need to sort the lines in alphabetical order. For example, in javascript, when importing a large number of modules, it is good practice to organize them alphabetically. Users of the vim editor can do this very simply. It is enough to select in the visual mode all the lines that need to be sorted and enter the command :sort. All rows are sorted!