Search code examples
reactjsaxiosrails-api

Component is not re-rendering on form submission. It only re-renders on a full page refresh


To summarize, I am submitting a POST request VIA axios and I am having the hardest time figuring out why it will not re-render my component that is displaying the newly added data (Where all of this is taking place).

Here is my post request (data is persisting correctly):

addNewLoad = (pickup_date, pickup_location, rate, delivery_date, delivery_location, loaded_miles, deadhead_miles, local, delivery_id) => {
        let config = {
            headers: {
                'Content-Type': 'application/json; charset=utf-8', "Accepts": "application/json",
            }
        }
     const instance = axios.create({baseURL: 'http://localhost:3001'})
      instance.post('/api/v1/pickup_deliveries', { pickup_date, pickup_location, rate, delivery_date, delivery_location, loaded_miles, deadhead_miles, local, delivery_id}, config)
        .then(response => {
        console.log(response)
          const pickup_deliveries = [ ...this.state.pickup_deliveries, response.data ]
          this.setState({pickup_deliveries})
        })
        .catch(error => {
            console.log(error)
        })
    }

Here is my component's state:

    state = {
        fiveDayView: [new Date(),
        addDays(new Date(), 1),
        addDays(new Date(), 2),
        addDays(new Date(), 3),
        addDays(new Date(), 4)],
        routeId: '',
        show: false,
        pickup_deliveries: [],
    }

So.. when I this.setState({pickup_deliveries}), I would expect my component to re-render. Not only that but within this component, I am currently pulling all the data from my Rails API and using said data to display within that component. I figured between the this.setState({pickup_deliveries}) and the re-rendering of the parent component where this data is coming from as this.props.apiData, there would be no issue with my component re-rendering and displaying the newly submitted data.

Sorry if that is confusing but I am at a loss here.


Solution

  • First of all is to check that you are not getting an empty array from the API, (check network tab). In that case you are not actually changing the array, but running a setState with the same value...

    setState doesn't re-render if there was no state change detected

    Second important thing when you update a state and use old value of the state you shouldn't access this.state, your code should look smth like this:

    this.setState((prevState) => ({
      pickup_deliveries: [...prevState.pickup_deliveries, response.data]); 
    

    Because state updates are async so you should never depend on this.state while updating state, as you might get an older state than the one you want to update.

    More on this topic https://reactjs.org/docs/state-and-lifecycle.html Quoting:

    State Updates May Be Asynchronous

    React may batch multiple setState() calls into a single update for performance.

    Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

    Third (workaround) to keep in mind in general is a workaround by add a parameter like 'lastRequestTimestamp' to the state to force state changes, specially when you are dealing with updating arrays or objects in state, this workaround is just to prove to yourself you are mutating the array which is not a state change as the array reference is still the same, but you shouldn't use this workaround except for debugging...