amit kumar

/amit08255

amit kumar

Welcome to my Social Blog

User Avatar

amit kumar

4y ago

React HOC holds some very powerful things inside that you cannot achieve easily with hooks and components.

We are going to see how React Higher Order Components can allow you to build better apps without having to add every responsibility inside components.

When should you prefer HOC over hooks?

Here are some scenarios when choosing HOC that are great instead of going on with hooks:

  • Share the same behaviour with multiple components without duplicating code.

  • Decoupling components with things like business logic.

  • Adding complex behaviours shared among multiple components without writing complex code.

Always prefer hooks when the logic or data is self-contain inside a component. If logic or data is being shared, then HOC is a great pattern to consider.

Story of a badly designed component

Every React component consists of a component. As the application grows, new changes and features are added. Suppose you created a page that handles multiple responsibilities:

  • Handling user authentication.

  • Logging.

  • Rendering page layout.

The most important thing to remember here is that you should never add multiple responsibilities to the same component. The more the component is aware of other things, the harder it is to maintain in the future.

Suppose the component looks like below:

HOC to the rescue!

The one of most powerful features that HOC can offer is called composition. The technique is that you create HOC which are responsible for a single thing and are not dependent on any other HOC. Then you use composition to create a single HOC which works like a pipeline of HOCs combining all their power together.

This is the magic function behind this composition technique:

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];

This is a very simple function. It just takes multiple functions and executes them from right to left. The parameter you pass to the composed function is passed to the right-most function. The other functions receive data returned by the function on their right as the parameter.

Below is an example of a HOC that creates a complex logic combining multiple small independent HOCs:

Let's make HOC curry!

Currying is a concept of functional programming. It is simply a function that takes one argument at a time and returns a series of functions where each function takes other arguments.

A simple example of a curried function is:

const add = x => y => x + y;
const increment = add(1);
const addTen = add(10);

increment(2); // 3
addTen(2); // 12

The same concept can be applied to HOCs.

Always keep this in mind when using HOC

HOCs are a very powerful feature of React and when used wisely, they will allow you to build great React apps. Always keep these rules in mind:

  • The logic or behaviour HOC provides should not be particular to the specific component. It should be shared behaviour.

  • It should not create multiple new props for components. It should only create a maximum of one new prop if that is very necessary.

  • Never make components dependent on a HOC. They should be totally independent.

  • No two HOCs should be coupled with each other. You should be able to use multiple HOCs in any order.

User Avatar

amit kumar

4y ago

Writing great code doesn't have to be complex. These simple tips will help you build React apps that are very easy to test, update and are super flexible.

Unfortunately we often build apps without thinking about how it will evolve to future changes.

How these techniques will be a life-saver

Here are some common scenarios in which these small techniques will prove a life-saver:

  • Easy to test.

  • Adapt to future updates.

  • Separation of business logic.

  • Predictable data flow.

Writing future-proof components

Always remember these thumb rules when writing components:

  • UI components should always be unaware of the network requests, business logic, or app state.

  • Components should be written like a pure function. It simply means that it should always render same data when provided same props.

Making evolution easy with HOCs

React Higher Order Component (HOC) is a component that takes a component and returns a component.

Always remember these thumb rules when writing HOC:

Architect your app for clean code

Never mix view render concerns, data processing and data fetching in a single place. Mixing everything will lead to a spaghetti architecture and will become painful in future.

Always make your component as dumb as possible. A component should always render same thing given the same state.

Flux architecture allows you to create a predictable data flow for your app. In this architecture event listeners listen for things like: user input handlers, network request handlers. When event listeners get them, it dispatches actions to the store. State is only be updated when an action is dispatched.

Use flux architecture based libraries like Reflux, Redux, etc. in below scenarios:

Using flux architecture will not only allow you to build highly flexible UI components, it will also allow you to separate things like business logic from your component. It will allow you to easy migration to different data fetching techniques. The predictable unidirectional data flow will make your app easy to debug and test.

User Avatar

amit kumar

4y ago

These small tips can save you large amount of time when dealing with states in a complex React application.

The stale state issue is common in React. The tips we are going to discuss will help you solve this issue in different scenarios.

Some common scenarios where this issue occurs

Here are a list scenarios when you get stale states in your code:

  • Inside a closure.

  • Inside an event handler callback.

  • Inside asynchronous function callback.

Here is a small project which uses asynchronous function callback and notice how the state update is not working. It is all because of stale state inside the callback function.

https://codesandbox.io/s/objective-dream-2esuky

Technique 1: Using function updates

This is very simple technique which allows you to deal with stale states. Use this technique in scenarios like: asynchronous callback, or inside a closure.

Here is how it works: Pass a function to the useState dispatcher. Passing a function to the dispatcher will allow you to access previous state value. The previous state value will be passed to the function when executed. To set the new state, you just need to return the new value from the function.

Here is the update version of same app above. It just have a small change i.e. a function is passed to the useState dispatcher. Notice how it's working perfectly within asynchronous callback.

https://codesandbox.io/s/heuristic-shaw-vfqr77

You can see we have used useRef here. The benefit of using useRef is that it allows you to keep track of a value without re-rendering. Since the object returned by useRef will be attached to component instance for it's entire life, it is a great way to make sure only one setInterval callback is created.

Technique 2: Using latest ref

This technique is very useful in scenarios such as: event handler callback. Here is how it works: You create a useRef object instance by passing your callback. Since the object created by useRef is created only once for the life of a component, it allows you to keep track of any value without re-rendering.

https://codesandbox.io/s/frosty-shape-lvfr58

You can see in the above app that the useRef is used to store a callback. The useLayoutEffect is used to register and remove previous callback. useLayoutEffect works same as useEffect except that here the callback passed is called before the change happened is painted on the browser screen.

Technique 3: Using callback memoization

This technique is very similar to previous one. Instead of storing the callback in ref.current , you pass that inside useCallback. The useCallback will return a memoized reference to the callback. Similar to useEffect you can pass a list of dependencies here as well. The advantage of this technique is that you can execute a set of things when the callback reference changes.

These simple techniques are very useful which will allow you to prevent issues in your application due to stale state data.

User Avatar

amit kumar

4y ago

There is one prop in React which is often used. Still, we don’t know how it works internally. The magical props we are talking about is the key prop.

The key prop is used by React to identify which items have changed, are added, or are removed. It is used commonly when you use elements inside an array.

Controlling react component instances

This is another little known secret about React key prop. The key prop in React allows you to control a component instance easily in just a single piece of code. It allows you to return the exact same component, but force React to unmount the previous instance of that component, and mount a new one.

Unmounting the previous instance simply means that all state that had existed in the component is completely removed and the component is reinitialized.

The above component is a very simple React component which increments the count every time you click on the button.

The above code adds a reset button near the counter button. When you click on the counter button, it’s count is incremented. When the reset button is pressed, it will reset the count to zero.

One important thing to notice here is that the App component is not sending any value to the counter. It is just changing the key every time a button is pressed.

That single piece of code is doing the reset magic. Whenever the key of a component is changed, the new instance is created. The new instance will always have a new set of states. This is why the reset button works and the counter gets to zero when reset is clicked.

A closer look inside the component

Below is the console log displayed when app is loaded:

Below is the console log displayed when counter value changes:

Below is the console log displayed when counter is reset:

If you look closely, you will notice that when the counter is reset i.e. its key is changed. The entire component is recreated. The state is reinitialized and the component is remounted.

This pattern is useful when you need to reset an entire component on a specific event or change. Use this pattern wisely, as changing keys initializes the component which can also result in performance issues when used in data heavy applications.

User Avatar

amit kumar

4y ago

𝟱 𝗦𝘁𝗲𝗽𝘀 𝗧𝗼 𝗕𝘂𝗶𝗹𝗱 𝗥𝗲𝗮𝗰𝘁 𝗖𝗼𝗺𝗽𝗼𝗻𝗲𝗻𝘁𝘀 𝗟𝗶𝗸𝗲 𝗔 𝗣𝗿𝗼

A component is a fundamental building block in React. In this article, we are going to look at a quick way to build truly maintainable, flexible, simple, and reusable components.

Building truly maintainable, and flexible components allow you to make your components future-proof. Software is changed very often as changes in requirements. If you don't write resilient components, it will become a pain to integrate new changes quickly and easily.

Unfortunately, building components that are not maintainable leads to nothing but pain and frustration for both the maintainer and user of the component.

𝗧𝗵𝗲 𝟰 𝗯𝗶𝗴𝗴𝗲𝘀𝘁 𝗺𝗶𝘀𝘁𝗮𝗸𝗲𝘀 𝗼𝗳𝘁𝗲𝗻 𝗺𝗮𝗱𝗲 𝘄𝗵𝗲𝗻 𝗯𝘂𝗶𝗹𝗱𝗶𝗻𝗴 𝗰𝗼𝗺𝗽𝗼𝗻𝗲𝗻𝘁𝘀

Here are some biggest mistakes leading to nothing pain and frustration when maintaining components.

  • Building complex components

  • Adding multiple responsibilities to single components

  • Building components coupled with several moving parts

  • Adding business logic in components

Learning this quick technique will not only allow you to build highly maintainable components in React. It will also allow you to make them more resilient and future-proof.

Here's how to step by step:

𝗦𝘁𝗲𝗽 𝟭: 𝗨𝗻𝗱𝗲𝗿𝘀𝘁𝗮𝗻𝗱𝗶𝗻𝗴 𝘁𝗵𝗲 𝗽𝗮𝘁𝘁𝗲𝗿𝗻

The pattern we are going to use for building react components is called compound components.

The compound component pattern has been used in the most popular react libraries. The reason for its popularity is that it allows you to build highly flexible components in react.

A simple example of compound component can be seen in HTML is <select> and <option> elements.

A simple example of this pattern is:

<Toggle onToggle={on => console.log(on)}>
    <ToggleOn>The button is on</ToggleOn>
    <ToggleOff>The button is off</ToggleOff>
    <ToggleButton />
</Toggle>

𝗦𝘁𝗲𝗽 𝟮: 𝗖𝗿𝗲𝗮𝘁𝗶𝗻𝗴 𝗮 𝗰𝗼𝗺𝗺𝗼𝗻 𝗽𝗮𝗿𝗲𝗻𝘁 𝗰𝗼𝗺𝗽𝗼𝗻𝗲𝗻𝘁

Now, the first step is to create a parent component that will provide API, data, and states common to its children. To share states and APIs from this component to all children under it, we can use react context.

Let's create a simple Toggle component that will display a message depending on its toggle state.

import * as React from 'react';

const ToggleContext = React.createContext();


function useEffectOnMount(cb, dependencies) {
    const ref = React.useRef(true);

    React.useEffect(() => {
        if (!ref.current) {
            return cb();
        }

        ref.current = false;
    }, dependencies);
}

function Toggle(props) {
    const [on, setOn] = React.useState(false)
    const toggle = React.useCallback(() => setOn(oldOn => !oldOn), [])

    useEffectOnMount(() => {
        props.onToggle(on)
    }, [on]);

    const value = React.useMemo(() => ({on, toggle}), [on])
    
    return (
        <ToggleContext.Provider value={value}>
            {props.children}
        </ToggleContext.Provider>
    );
}

𝗦𝘁𝗲𝗽 𝟯: 𝗖𝗿𝗲𝗮𝘁𝗲 𝗮 𝗴𝘂𝗮𝗿𝗱 𝗵𝗼𝗼𝗸

This guard hook will allow you to prevent using the child components outside the parent context.

function useToggleContext() {
  const context = React.useContext(ToggleContext);

  if (!context) {
    throw new Error(
      'This component cannot be used outside Toggle',
    );
  }

  return context;
}

𝐒𝐭𝐞𝐩 𝟒: 𝐂𝐫𝐞𝐚𝐭𝐞 𝐜𝐡𝐢𝐥𝐝 𝐜𝐨𝐦𝐩𝐨𝐧𝐞𝐧𝐭𝐬

Now you can build child components for the parent Toggle component. One thing to keep in mind is that these child components can be used directly inside the toggle. It simply means that you can pass their props directly to them. No need to add them to the parent component. It will allow keeping the parent and child decoupled from each other.

The concept here is that the parent component should not be aware of what the child component consists of.

function ToggleOn({children}) {
    const {on} = useToggleContext();
    return on ? children : null;
}

function ToggleOff({children}) {
    const {on} = useToggleContext();
    return on ? null : children;
}

function ToggleButton(props) {
    const {on, toggle} = useToggleContext();
    return <Switch on={on} onClick={toggle} {...props} />;
}

𝐒𝐭𝐞𝐩 𝟓: 𝐂𝐨𝐦𝐩𝐨𝐮𝐧𝐝 𝐜𝐨𝐦𝐩𝐨𝐧𝐞𝐧𝐭 𝐢𝐧 𝐚𝐜𝐭𝐢𝐨𝐧

function App() {
  return (
    <Toggle onToggle={on => console.log(on)}>
      <ToggleOn>The button is on</ToggleOn>
      <ToggleOff>The button is off</ToggleOff>
      <ToggleButton />
    </Toggle>
  )
}

There is a toggle status label added above ToggleButton. This component is so flexible that you can add/remove any part in the Toggle app without having to change anything in the Toggle component.

An important thing to remember here is that this pattern must be used in cases when your component has multiple moving parts (children). Do not use it with atomic components like: Button, Input where there are no multiple moving parts.