The Journey of #100DaysOfCode (@sourabhbagrecha)

#Day39 of #100daysofcode

Today I learned about how to populate an array of ObjectIds inside a document using mongoose.
I knew that .populate() method works when we have an ObjectId as the value of a key, but didn’t know it can work for an array of ObjectIds, therefore I decided to do a POC for this, and here’s the sample code to do the same:

3 Likes

#Day40 of #100daysofcode

Today I learned about Providers and how to utilise various Hooks through React Contexts. It’s really fun to see how different parts of React combine together in such an elegant and consistent manner that they feel so natural and intuitive.

2 Likes

#Day41 of #100daysofcode

Today I learned how to create custom hooks on top of React-provided hooks. It’s pretty easy and straightforward to create a custom hook once we understand what all functions, values and helpers need to be returned from a custom hook and how we can utilize React provided hooks and add some business logic that we can reuse at multiple places inside our components.

2 Likes

#Day42 of #100daysofcode

Today I learned how to create custom providers on top of the React provided Contexts.

3 Likes

#Day43 of #100daysofcode

Today I created a local-storage-React-hook on top of the React-provided useState hook:

function useLocalStorageState(
  key,
  defaultValue = '',
  {serialize = JSON.stringify, deserialize = JSON.parse} = {},
) {
  const [state, setState] = React.useState(() => {
    const valueInLocalStorage = window.localStorage.getItem(key)
    if (valueInLocalStorage) {
      return deserialize(valueInLocalStorage)
    }
    return typeof defaultValue === 'function' ? defaultValue() : defaultValue
  })

  const prevKeyRef = React.useRef(key)

  React.useEffect(() => {
    const prevKey = prevKeyRef.current
    if (prevKey !== key) {
      window.localStorage.removeItem(prevKey)
    }
    prevKeyRef.current = key
    window.localStorage.setItem(key, serialize(state))
  }, [key, state, serialize])

  return [state, setState]
}

The above hook is creating a very high level of abstraction as well because it hides the implementation of how it is handling the local storage sync as well the serialization & deserialization while saving and retrieving the state from the local storage.

2 Likes

#Day44 of #100daysofcode

Today I learned about lazy initializers while using hooks. Basically, they help us optimize our components’ performance and make the state initialization less expensive in terms of compute resources.
If we want to get our state from the local storage of the browser, we would typically write the following code to get the value and store it in a local state variable like this:

const [user, setUser] = useState(JSON.parse(window.localStorage.getItem("user")))

But reading something from the localStorage is a very expensive operation, and this process happens on every render, therefore we might want to optimize it.
We can do this by passing a function to useState, and since creating functions in JavaScript is more efficient than performing the same IO operation on every render, we can implement the same as below:

const [user, setUser] = useState(() => JSON.parse(window.localStorage.getItem("user")))
2 Likes

#Day45 of #100daysofcode

Today I learned about Error Boundaries in React. The idea behind error boundaries is that if one part/component of your UI breaks it should not break the whole app. Basically, it’s a React component that catches JavaScript errors anywhere in the children components and displays a fallback UI in place of the error-causing component.

2 Likes

#Day46 of 100daysofcode

Today I learned about some techniques using which we can use React Query not just for making HTTP requests but to implement utilities in our code. While the React-Query’s official documentation states that it is used to:

Fetch, cache and update data in our React and React Native applications all without touching any “global state”.

But we can use it to make utilities like a StopWatch, Throttled Logger, Web Workers, GPS utilities etc. The video: Five Clever Hacks for React-Query and SWR helped me in discovering these capabilities.

2 Likes

#Day47 of #100daysofcode

Today I learned about the useReducer React Hook, which helps us in managing the state for our component and it is similar to the useState hook, but useReducer becomes really helpful when we want to separate the state logic from the component that is trying to manage the state.
useReducer also comes in handy when we have a single state object that is getting used and mutated in multiple components.

So basically, when we want to maintain a user profile using useState, we will use the following syntax:

const [profile, setProfile] = useState({
  name: 'Sourabh Bagrecha',
  medium: 'medium.com/@sourabhbagrecha',
  github: 'github.com/sourabhbagrecha',
  linkedin: 'linkedin.com/in/sourabhbagrecha'
});

Whenever we want to make changes to the profile, we can simply do that in the following manner:

setProfile({...profile, name: "SOURABH BAGRECHA"})

But this approach is prone to bugs and can cause errors if the state is not handled in a standard way throughout different children components.
To overcome this, we can use the useReducer Hook, there are multiple ways to tackle this using useReducer, one of them is using it in the following manner:

const initialState = {
  name: 'Sourabh Bagrecha',
  medium: 'medium.com/@sourabhbagrecha',
  github: 'github.com/sourabhbagrecha',
  linkedin: 'linkedin.com/in/sourabhbagrecha'
}

const profileReducer = (state, action) => { 
  return {...state, ...action}
};

const [profile, setProfile] = useReducer(profileReducer, initialState);

The useReducer setup is a little bit more complex than the useState setup, but now, updating the profile state has become very seamless:

setProfile({name: "SOURABH BAGRECHA"})

As we can see, we don’t have to worry about the state of the rest of the profile object. All we did above is updated the name property and our profile-reducer will take care of everything.

2 Likes

#Day48 of #100daysofcode

Today I continued my useReducer Hook learning journey, and I was surprised to know that we can implement Redux’s dispatch API using this hook.
Let’s take a look at how we use our reducer to implement the Traditional Dispatch Object and use it to manage our state without using a third-party library:

// Here we are first checking the type of the action and on the basis
// of that we will choose the case that will set the state as intended
const profileReducer = (state, action) => {
  switch (action.type) {
    case 'CHANGE_NAME': return {...state, name: action.name}
    case 'CHANGE_MEDIUM_URL': return {...state, medium: action.medium}
    case 'CHANGE_GITHUB_URL': return {...state, github: action.github}
    case 'CHANGE_LINKEDIN_URL': return {...state, linkedin: action.linkedin}
    default: {
      throw new Error(`Unhandled action type: ${action.type}`)
    }
  }
}

const initialState = {
  name: 'Sourabh Bagrecha',
  medium: 'medium.com/@sourabhbagrecha',
  github: 'github.com/sourabhbagrecha',
  linkedin: 'linkedin.com/in/sourabhbagrecha'
}

const [state, dispatch] = useReducer(profileReducer, initialState);

Now, we will take a look at how we can use this dispatch function to update our state accordingly:

dispatch({type: 'CHANGE_NAME', name: 'SOURABH BAGRECHA'});

All we had to do was mention the type of action and the value using which we want to update the state and we don’t have to care about how the state is getting manager, and hence it becomes very handy when dealing with a state across many different components without worrying about the bugs it may cause.

2 Likes

#Day49 of #100daysofcode

Today I learned how to create custom hooks on top of the useCallback hook provided by React. The process is somewhat similar to creating a useState custom hook, but there are some more moving parts like function callback etc.

2 Likes

#Day50 of #100daysofcode

:star_struck: Day FIFTY? :star_struck: :star_struck: :star_struck: :star_struck: :star_struck:

Today I learned about how to create custom hooks using useReducer, useCallback, and useEffect together to manage state efficiently across components.
It was really fun to see how all these building blocks get combined together so elegantly in the end.
So here’s the custom useAsync hook that I created using all the above mentioned React provided hooks:

Using the following code, I am creating a generic hook that can be used to implement state management logic that are dependent on some asynchronous tasks like: asyncCallback in this case.

const useAsync = (asyncCallback, initialState) => {
  const [state, dispatch] = React.useReducer(asyncReducer, {
    status: 'idle',
    data: null,
    error: null,
    ...initialState,
  })

  React.useEffect(() => {
    const promise = asyncCallback()
    if (!promise) {
      return
    }

    dispatch({type: 'pending'})
    promise.then(
      data => {
        dispatch({type: 'resolved', data})
      },
      error => {
        dispatch({type: 'rejected', error})
      },
    )
  }, [asyncCallback])

  return state
}

And here we are using the above useAsync hook to get the state by providing a memoized version of asyncCallback along with the initial state:

  const asyncCallback = React.useCallback(() => {
    if (!pokemonName) return false
    return fetchPokemon(pokemonName)
  }, [pokemonName])

  const state = useAsync(asyncCallback, {
    status: pokemonName ? 'idle' : 'pending',
  })
3 Likes

#Day51 of #100daysofcode

Today I worked on my Expengo cross-platform mobile app based on React Native and have started implementing what I learned in the past few days while digging deep into react.
The first optimization that I performed was lazy initialization in order to improve the render & UI update performance. I will also try to replace useState with useReducer wherever I am sharing a complex state object across components.

3 Likes

#Day52 of #100daysofcode

Today I learned about a really cool Context-Provider strategy that we can use to avoid any Context consumption outside of the Provider. Basically, we can create a custom hook that will act as a proxy to the whole useContext implementation.
An example/demo is worth a thousand words:

// creating a PokemonCacheContext to manage state across children components
const PokemonCacheContext = React.createContext()

// creating a PokemonCacheProvider to use it as a wrapper and 
// make the values available to a component tree
const PokemonCacheProvider = ({children}) => {

  // This provider will use the reducer and expose the returned value via the value prop
  // and all of its children component will be able to access them without any prop drilling.
  const [cache, dispatch] = React.useReducer(pokemonCacheReducer, {})
 
  return (
    <PokemonCacheContext.Provider value={[cache, dispatch]}>
      {children}
    </PokemonCacheContext.Provider>
  )
}

// We are creating this custom hook in order to avoid any calls to the 
// PokemonCacheContext outside of the PokemonCacheProvider 
const usePokemonCache = () => {
  const value = React.useContext(PokemonCacheContext)
  if (!value)
    throw Error(
      'usePokemonCache should only be called within PokemonCacheProvider.',
    )
  return value
}
2 Likes

Hello @SourabhBagrecha :wave:

Amazing progress on your #100Days and super happy to see your commitment towards it. I hope you are enjoying your journey as much as I did. :blush: Many Congratulations on crossing the half mark… :partying_face: :clap:

You are now my go-to person for React Native Mobile app questions :wink: I may take time to read through all but will need your help on creating a backend with Atlas for a mobile app.

Keep inspiring and wish you the best in your remaining 50 days. :four_leaf_clover:

Cheers, :performing_arts:

3 Likes

#Day53 of #100daysofcode

Today I learned about the useLayoutEffect hook. This React hook is very similar to the useEffect hook, and it basically executes the callback whenever the component gets rendered or any of the dependencies mentioned in the second argument got updated.

But the actual difference comes into the picture when we talk about how those effects are executed.
useEffect will not block the browser painting, i.e. useEffect will wait for React to render the component before executing the callback, whereas
useLayoutEffect will run synchronously after React has performed all the DOM mutations. That means, it can be really helpful when we want to make DOM updates that are observable from a human eye.

The following code will scroll the container to the bottom once the browser is done painting the screen(which is also referred as rendering the component).

  React.useEffect(() => {
    containerRef.current.scrollTop = containerRef.current.scrollHeight
  })

But the following code will scroll the container before the browser even gets the chance to paint the screen, therefore it will smoothen the User Experience.

  React.useLayoutEffect(() => {
    containerRef.current.scrollTop = containerRef.current.scrollHeight
  })
3 Likes

#Day54 of #100daysofcode

Today I learned about the React-provided useImperativeHandle hook. It is basically used to customize the instance value that is exposed to parent components when using ref.
To utilize this hook, we need to wrap the concerned component with forwardRef.
For e.g, in the

function MessagesDisplay({messages}, ref) {
  const containerRef = React.useRef()

  // All the properties that are getting declared in this useImperativeHandle hook 
  // callback, they will be exposed to the parent component
  React.useImperativeHandle(ref, () => ({
    scrollToBottom,
    scrollToTop,
  }))

  function scrollToTop() {
    containerRef.current.scrollTop = 0
  }
  function scrollToBottom() {
    containerRef.current.scrollTop = containerRef.current.scrollHeight
  }

  return ( ...some JSX...  )
}

// Here, we are forwarding all the ref from the parent component 
// to the MessageDisplay component.
MessagesDisplay = React.forwardRef(MessagesDisplay)

function App() {
  const messageDisplayRef = React.useRef()

  const scrollToTop = () => messageDisplayRef.current.scrollToTop()
  const scrollToBottom = () => messageDisplayRef.current.scrollToBottom()

  return (
    <div className="messaging-app">
        <button onClick={scrollToTop}>scroll to top</button>
      </div>
      <MessagesDisplay ref={messageDisplayRef} messages={messages} />
      <div>
        <button onClick={scrollToBottom}>scroll to bottom</button>
      </div>
    </div>
  )
}

export default App
3 Likes

#Day55 of #100daysofcode

Today I learned about the useDebugValue hook.
The main use case of this hook is to debug values as they change and inspect them easily in the React Developer tools and this allows us to test certain feature and changes without any side effects in the main application state.

4 Likes

#Day56 of #100daysofcode

Today I finally finished my Advanced React Hooks learning. It was so insightful to learn about these not-so-common React hooks and how they help us in writing efficient code that performantly updates the DOM by giving providing an API that abstracts away all the internal implementations.

4 Likes

#Day57 of #100daysofcode

Today I was working on my Skunkworks project. Skunkworks is a 5-day internal event at MongoDB where we dive in to collaborate across teams on an idea, passion project, and prototypes away from the critical path, basically an internal hackathon.
This is my third Skunkworks, and I am super excited for this one.
When I was building my first React Native based expense-manager using Atlas Device Sync, I came across a feature where I wanted to perform analytics on the data stored on the user’s device.
Though Realm SDKs provide all the features I needed to build an offline-first Mobile App, but I got really sad when I learned that Realm SDK does not provide my favorite MongoDB feature: Aggregation Pipelines.

Therefore, I couldn’t think of a better project than to bring these Analytical capabilities to the Realm SDK so that we can perform Analytics even when there’s no internet.

4 Likes