TILMarch 22, 2020by Dmitry Sokolov

Absolute imports in Next.js

When I was working on my first project with Next.js I spent a lot of time to find how to use absolute imports. The solution turned out to be quite simple. You need to indicate this resolve option in your next.config.js file:

module.exports = {

  webpack(config) {


    return config;



Or if you want to add absolute path only for one directory you can use alias:

module.exports = {

  webpack(config) {

    config.resolve.alias['components'] = path.join(__dirname, 'components');

    return config;



TILJanuary 06, 2020by Dmitry Sokolov

Problem with download file in Google Chrome

I encountered such a problem when I tried to download base64 decoded file with a size over 1mb in Chrome.

I had a function like this:

export const downloadBase64File = (fileData, fileName) => {

  const fileUrl = `data:application/octet-stream;base64,${fileData}`;

  const link = document.createElement('a');

  link.href = fileUrl;

  link.setAttribute('download', fileName);





It worked good in FireFox but didn't work in Google Chrome. And I found the following solution:

const urlToFile = (url, filename) => {

  return fetch(url)

    .then((res) => {

      return res.arrayBuffer();


    .then((buf) => {

      return new File([buf], filename);



export const downloadBase64File = (fileData, fileName) => {

  const fileUrl = `data:application/octet-stream;base64,${fileData}`;

  urlToFile(fileUrl, fileName).then((file) => {

    const blob = new Blob([file], { type: 'application/octet-stream' });

    const blobURL = window.URL.createObjectURL(blob);

    const link = document.createElement('a');

    link.href = blobURL;

    link.setAttribute('download', fileName);






It works correctly for all browsers.

TILDecember 26, 2019by Dmitry Sokolov

Environment variables in NEXT js

How to get env variables to your app code in NEXT.js application?

It’s not a big deal, but if you set ‘NODE_ENV’ for env in next.config.js it will not work correctly.

Anytime you will have ‘production’ (default value at build time) for any environments (staging, integration, production).

Just use another name instead ‘NODE_ENV’, for example ‘ENV’.

// next.config.js


module.exports = {

  env: {

    ENV: process.env.NODE_ENV,



It will be available in your app code

export default () => <div>{process.env.ENV}</div>

TILOctober 10, 2019by Maxim Romanov

How quickly and easily run a local server with fake api data (mocks)?

Sometimes you need to develop a frontend part of a project without a ready-made api, knowing only its structure. In this case, using json-schema-faker, you can generate fake data (mocks) and deploy it to your local server.

Firstly u will need to install json-schema-faker package

yarn add json-schema-faker

Then open the package.json file and add scripts with the following

// ...

"scripts": {

  // ...

  "start-mockapi": "json-server --watch ./mocks/api/db.json --port 3001",

  "generate-mock-data": "node ./generateMockData",


After installation, you will need to describe the structure in ./mocks/dataSchema.js of future mocks. You can find more information here.

const schema = {

  reports: {

    type: 'array',

    minItems: 5,

    maxItems: 10,

    items: {

      id: {

        type: 'integer',

        unique: true,

        minimum: 1,

        maximum: 1000,


      title: {

        enum: ['production', 'azure data', 'azure data 2'],


      logo: 'https://picsum.photos/200'




module.exports = schema;

Copy paste script for generating mock data from here in ./generateMockData.js and run the following

yarn generate-mock-data && yarn start-mockapi

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() {


        try {

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



          return res;

        } catch (e) {



          return e;





    [action, ...dependeces],


  return [asyncAction, loading, isError];


Now you can use this hook in your functional component.

// …

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

// …


TILAugust 02, 2019by Maxim Romanov

How to blur a screen in React Navigation

Screens overlap each other in stackNavigator. React Navigation provides us not only with changing the background color of these screens, but also controlling their transparency.

To make the screen background blur, we first need to make the screens transparent.

import { createStackNavigator } from 'react-navigation';

export default createStackNavigator(







    mode: 'modal',

    cardStyle: { opacity: 1 },

    transparentCard: true,



And then use blurView as background.

import React from 'react';

import { BlurView } from '@react-native-community/blur';

import Styled from 'styled-components';

function BlurModal() {

  return (

    <BlurWrapper blurType="light" blurAmount={20}>

      <Text>Modal with blur background</Text>




const BlurWrapper = Styled(BlurView)`

  position: absolute;

  top: 0;

  left: 0;

  bottom: 0;

  right: 0;


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, {}, {



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

import apiAdapter from './apiAdapter'


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

const apiAdapter = createAdapter(


  { withCredentials: true },








Live example

TILJuly 17, 2019by Maxim Romanov

How to handle 401 unauthorized error in a Redux React application

In response to a client request, the server may return a 401 Unauthorized error. You must correctly catch it, for example, clear the state and redirect to the authorization page. To solve this problem, we wrote a custom Middleware which, in our opinion, is the best solution.

import * as actions from 'actions';

const authInterceptor = ({ dispatch }) => (next) => (action) => {

  if (action.status === 401) {


  } else {




TILApril 22, 2019by Dmitry Sokolov

Integrate Drawer inside Stack Navigation in React Native

I wanted to use more than one navigation in a React Native app.

The documentation didn’t give a clear way to implement this.

Here is what you can do on purpose to add several types of navigation in your React Native app:

import { createStackNavigator, createDrawerNavigator } from 'react-navigation';

import * as Screens from './screens/index';

import Drawer from './components/DrawerMenu';

import getDrawerWidth from './utils/scale';

const AppStackNavigator = createStackNavigator({

  home: {

    screen: Screens.MainScreen,


  about: {

    screen: Screens.AboutScreen,



const AppNavigator = createDrawerNavigator(


    home: {

       screen: AppStackNavigator,




    contentComponent: Drawer,

    drawerWidth: getDrawerWidth,

    headerMode: 'none',



export default AppNavigator;

TILMay 14, 2019by Dmitry Sokolov

JS: Parsing URL

So far, I have used the indexOf operator or regular expressions to get query string values. Today I learned how to make it easier using the URLSearchParams API:

// Assuming "?post=1234&action=edit"

let urlParams = new URLSearchParams(window.location.search);

console.log(urlParams.has('post')); // true

console.log(urlParams.get('action')); // "edit"

console.log(urlParams.getAll('action')); // ["edit"]

console.log(urlParams.toString()); // "?post=1234&action=edit"

console.log(urlParams.append('active', '1')); // "?post=1234&action=edit&active=1"

Important: Does not work in IE

TILMay 01, 2019by Suhomozgy Andrey

Typeahead async requests throttling

As everybody else have some legacy code (who does not have it?), and yesterday we faced with problem.

Our internal app have search panel where users could write and get related results. But search was written with typeahead and without any throttling. So it's triggered full text search on backend side on every input change which leads to DB connection pool exhaustion.

We didn't found any ready to use solutions, so we added following fix:







    async: true

    source: (query, syncResults, asyncResults) ->

      href = self.href

      # Added getAsyncResults call to throttle requests:


        () ->


            url: href


              query: query

            dataType: 'json'


            (data, textStatus, jqXHR) ->





where getAsyncResults defined before typeahead init:

# throttle is lodash function

getAsyncResults = _.throttle(((fn) ->


  ), 300,

  { ... })

Would be happy if someone find this simple solution helpfull.

TILApril 23, 2019by Suhomozgy Andrey

Trick: filter falsy values out of an array?

Lets say you need to filter all falsy

0, undefined, null, false, ''(empty string), NaN

values from array.

Of course you can use following construnction:


    .map(item => {

        // ...


    // Get rid of falsy values

    .filter(item => item);

Since the values we don't want aren't truthy, the filter above removes those falsy items.

Did you know there's a clearer way with Boolean?


    .map(item => {

        // ...


    // Get rid of falsy values


TILApril 17, 2019by Suhomozgy Andrey

Add conditional properties in JS objects

How conditionaly add properties to object?

As it turned out, it's pretty simple:

const user = { id: 1, name: 'Suhomozgy Andrey' }

const position = 'Frontend Developer'

const userWithPosition = {


  id: 2,

  ...(position && { position })


userWithPosition //=> { id: 2, name: 'Suhomozgy Andrey', position: 'Frontend Developer' }

TILMarch 20, 2019by Suhomozgy Andrey

Get most performant function

Let's say you need to determine which function is execute faster.

Write a function that take array of functions and iterates each of them a certain number of times.

Will use the difference in performance.now() values before and after to get the total time in milliseconds each iteration running.

Play with iterations argument to get more or less reliable results.

const mostPerformantFunction = (fns, iterations = 10000) => {

  const times = fns.map(fn => {

    const before = performance.now();

    for (let i = 0; i < iterations; i++) fn();

    return performance.now() - before;



  return times.indexOf(Math.min(...times));



  () => {

    [1, 2, 3, 4, 5, 6, 7, 8, 9, '10'].every(el => typeof el === 'number');


  () => {

    [1, '2', 3, 4, 5, 6, 7, 8, 9, 10].every(el => typeof el === 'number');


]); // 1

TILMarch 20, 2019by Alexander Blinov

How to download files with Axios

A simple example using the Blob() constructor:

export function someFunction(values) {

  return (dispatch) => {


    const method = 'GET';

    const url = 'http://go.api/download_file';






        responseType: 'blob', //important


      .then(({ data }) => {

        const downloadUrl = window.URL.createObjectURL(new Blob([data]));

        const link = document.createElement('a');

        link.href = downloadUrl;

        link.setAttribute('download', 'file.zip'); //any other extension







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">

    {/* ... */}


      {/* ... */}

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



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 }),


  // App.js

  import Button from './Button';

  // ...

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

Live example

TILFebruary 20, 2019by Alexander Blinov

Custom onChange in React Final Form

Let's take a case when we need to call our own function to change a state of a specific field in a form (our react final form).

Here is a way to do the exact that:

You should pass your function as a parameter and after that just call it inside of the onChange method


const FormGroupAdapter = ({ input, inputOnChange }) => {

    const inputProps = {


        onChange: e => {


            inputOnChange && inputOnChange(e);



    return <input {...inputProps} />;


const handleChange = event => {

    console.log("!!!", event.target.value);


const App = () => (



        render={({ handleSubmit, reset, submitting, pristine, values }) => (

            <form onSubmit={handleSubmit}>


                    <label>some label</label>












Live example

TILFebruary 20, 2019by Suhomozgy Andrey

How to display numbers with currency formatting in JS?

Use Intl.NumberFormat to enable country / currency sensitive formatting.

const toCurrency = (n, curr, LanguageFormat = undefined) =>

  Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n);

toCurrency(123456.789, 'EUR'); // €123,456.79  | currency: Euro | currencyLangFormat: Local

toCurrency(123456.789, 'RUB'); // RUB 123,456.79  | currency: Ruble | currencyLangFormat: Local

toCurrency(123456.789, 'RUB', 'Ru-ru') // 123 456,79 ₽  | currency: Ruble | currencyLangFormat: Russian

toCurrency(123456.789, 'USD', 'en-us'); // $123,456.79  | currency: US Dollar | currencyLangFormat: English (United States)

toCurrency(123456.789, 'USD', 'fa'); // ۱۲۳٬۴۵۶٫۷۹ ؜$ | currency: US Dollar | currencyLangFormat: Farsi

toCurrency(322342436423.2435, 'JPY'); // ¥322,342,436,423 | currency: Japanese Yen | currencyLangFormat: Local

toCurrency(322342436423.2435, 'JPY', 'fi'); // 322 342 436 423 ¥ | currency: Japanese Yen | currencyLangFormat: Finnish

TILJanuary 29, 2019by Suhomozgy Andrey

Passing events between browser tabs without WebSockets

What if need to pass some event from one browser tab to each others? And we don't have WebSockets...

It turns out that localStorage raises events 😍

Namely, events are triggered when an item is added, deleted, or changed in another context. In essence, this means that when you change localStorage in one tab, other tabs can find out about this by listening to the storage event of the global window object. For example:

  window.addEventListener('storage', function (event) {

    console.log(event.key, event.newValue);


Of course, there are some restrictions on use (you can read about them here https://www.w3.org/TR/webstorage/), but for simple cases it is match perfect.

TILJanuary 29, 2019by Alexander Blinov

Rename the key name in the javascript object

How to rename the key name in the javascript object? That’s easy!

Lets create function to do that:

const renameKey = (object, key, newKey) => {

  const clonedObj = clone(object);

  const targetKey = clonedObj[key];

  delete clonedObj[key];

  clonedObj[newKey] = targetKey;

  return clonedObj;


Here is clone function:

const clone = (obj) => Object.assign({}, obj);


let contact = { 

    id: 1, 

    name: "contact name"


contact = renameKey(contact, 'id', 'value');

contact = renameKey(contact, 'name', 'label');

console.log(contact); // { value: 1, label: "contact name" };