React Dom Rendering on Callback to a Mother Component

I just wanted to share what I learned recently regarding how React only updates the specific render it needs to, and I would have thought otherwise.

My app has a layout like this

App > Posts > Post

App controls all the state and renders Posts, Posts maps through all the this.state.posts and renders each one Post, and Post renders the post details.

I wanted to toggle between that Post view and a PostForm if the user clicked edit. See here a short example:

So I passed a function from Post to App handling edit and changing this.state.edit from false to true.

Now I just need to know where to put my ternary regarding which component to render based on this.state.edit.

So first thing that came to mind was that App would re-render because state within App changed (the this.state.edit now is true, and is located in App), so in my Posts map, I found the post that matched the id of the edit (which I had also added to state), and put my ternary in there.

post.id === updatedPost.id && this.state.edit ? <PostForm …. /> : <Post … />

And I was all excited to see it work, and nothing happened. Nothing changed. Ok, maybe my code was a little wrong, let’s load up our handy debugger and watch each step happen from the handleUpdate callback from Post to App, and go step by step.

I watched the callback head into the App, update the state, so far so good. Now I am ready to see it head into the render of App, and then load up the Posts map, but much to my surprise, the very next step was the Post render. React really held in memory that we are in the Post component, and as soon as we finish our callback, even though it’s in another component, it went straight back to where it was and did not need to update the whole DOM again. Pretty amazing.

So to make this form and Post toggle ended up being simpler than expected, because I didn’t even have to check if post.id === updatedPost.id. React already remembered the scope we were in, and went back only to that one instance of Post component, and updated that into a form.

No wonder React can be so fast, here I had 40 posts on a page, and instead of re-rendering all 40 posts, it knew only to render that small single Post or Form with very little code and logic.

React does not fail to amaze me.

 

Dispatching Redux

When I think of redux this is what comes to mind:

And that’s not because I was ready to have my brain checked when starting to learn React/Redux 🙂

I am writing this post to explain to you how I think of React/Redux, and how it helped me better understand it, and I hope it can help you too!

This is not a detailed walk through, for tutorials on React/Redux I can recommend:

Among many of the fabulous resources out there people have taken the time out to help us understand this framework.

So now back to my ambulances…

If we want to have a function that will not be called on load, but rather upon an action — for example an onClick function, we cannot put the () after the function as that will call it as soon as the page loads it. We can’t put the function without the () because that will just show what’s contained in the function instead of ever running it. We need to somehow bind that function to the event so it can be triggered exactly when we want it to with the applicable event/data.

In redux to accomplish this we  dispatch the function. Here is a code example from my repo – https://github.com/mxdavis/timer-billing-client/

import {removeTask} from '../../redux/actions/tasks/tasks'

....

  handleDelete = event => {
    event.preventDefault();
    ...
    this.props.removeTask(this.state)
}

render(){
  return(
     ...
      <div className="uk-width-2-2 uk-text-center">
         <button
           onClick={this.handleDelete} 
           type="delete"
           value="Delete Task"
           >X</button>
        </div>
      ...
   )
}

...

const mapDispatchToProps = dispatch => {
  return bindActionCreators(
    { fetchClients, addTask, removeTask }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(AddTask);

 

Here we have the a delete button that dispatches an action removeTask onClick. Since I use mapDispatchToProps I do not need to put dispatch(removeTask(this.state)) instead if I use this.props.removeTask(this.state), the mapDispatchToProps already bound dispatch to removeTask and I can access it through props.

This function is an action and looks like so:

export function removeTask(task){
  return {
    type: 'REMOVE_UNBILLED_TASK',
    task
  }
}

The file was able to find it, because I had imported it previously (see the top line of the previous code snippet). I could have had this function locally in the folder, but to keep the file from getting too heavy I put it in an actions folder.

Now this action is being dispatched from the emergency call center to all the medics who have their radios always on waiting to accept the signal. And the medic in the right area that fits the type needed responds to the action and does what it is told to do.

This is where the reducers come in.

The reducers are set up in the store (normally through a combinedReducers, as there are frequently more than one reducer). Here is an example of my file that sets up redux store:

import {createStore, applyMiddleware, combineReducers } from 'redux'
import thunk from 'redux-thunk'

import clients from '../reducers/clients/clients'
import tasks from '../reducers/tasks/tasks'
import fetchingData from '../reducers/fetchingData'

const reducers = combineReducers({
  tasks, clients, fetchingData
})

const middleware = [thunk]

export default createStore(
  reducers, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), 
  applyMiddleware(...middleware)
)

 

The combineReducers is combining all my reducers, and we pass this into createStore.

What this does is give the reducers each their own radio that is turned on and ready to listen when an action is being called just like when a person starts working as a medic he is given a radio that he needs to leave on and always listen to.

If you put a debugger in a reducer, you will see that it is called each time the page/app renders, even if the action never called that particular one, or if even any action is called at all.

Reducers are case statements looking for a string that matches the action.type that the action sent out.

With each state update, it checks to see if the action.type has been called, and if it does it will run the code inside.

Back to our analogy, when a medic’s radio hits based on certain criteria, he will receive the follow up instructions, while everyone else’s radio will stay silent as they do not need to be disturbed yet. If we had all our medics responding to every call they would be running all over the place, and not actually showing up to anyone on time and in an efficient manner. And not to mention, they’d probably all quit, and work for a more efficient team that knew how to alert only medics in the vicinity or medics with the equipment necessary for the call…

Here is what my reducer looks like that will match the string ‘REMOVE_UNBILLED_TASK’:

export default function tasks(state = {
    unbilled_tasks: [], 
    billed_tasks: []
}, action) {
  switch (action.type) {
  ...
    case 'REMOVE_UNBILLED_TASK':
      const tasksWithoutDeletedTask = state.unbilled_tasks.filter(t => t.task_id !== action.task.task_id)
      return Object.assign({}, state, {unbilled_tasks: tasksWithoutDeletedTask})
    default:
      return state;
  }
};

 

Always remember that since every reducer function gets called with each render we need to include a default option in our case statement that returns the current state, so that we do not end up with an empty state each time the page updates.

Keep this in mind when creating your reducers.

So to sum up my analogy, our medics/reducers always have their radios on waiting to be called, and this we set up by creating the redux store with our combinedReducers (unless we have only one reducer then we just put that one reducer in the store). The functions from the component dispatch actions only when they are triggered, and not upon load of the page (like onClick, or onChange..), which our component (medical center) sends the action.types to the correct (medic) reducer (instead of running all actions on load, and sending all medics on every call which would be extremely inefficient and time consuming!).

I hope I was able to help some people better understand the redux cycle. This was my first react/redux project and this concept really helped getting me started.

Copyright Loving to Code 2025
Tech Nerd theme designed by Siteturner