Why reducer with array.sort doesn't trigger re-render?

Viewed 379

I've got a problem with re-rendering table in React.
So at first is how it looks like link
When I fetch data from SWAPI (I'm doing it in action) and passing it into reducer, it works fine and table component re-renders without any trouble.
But when I'm trying to sort it via SORT_RESULTS reducer, it just doesn't do anything with table itself. It actually modifies state as FETCH_DATA reducer do, but doesn't do anything, however I can log sorted information and make sure it was sorted as intended.
Thanks in advance for your help!

// actions.ts
export const onDataFetched = (currentPage: number = 1) => (
    async (dispatch:any) => {
        let data: {} = await fetch(`http://swapi.dev/api/people/?page=${currentPage}`)
                              .then(response => response.json())
        const dataToReturn = {
            type: 'FETCH_DATA',
            payload: data
        }
        dispatch(dataToReturn)
    }
)

// reducers.ts
case FETCH_DATA:
    // returns new state object
    return {
        ...state,
        swapi_data: {
            ...action.payload
        }
    }
// actions.ts
export const onSortResults = (payload: string) => (
    (dispatch:any) => {
        dispatch({type: 'SORT_RESULTS', payload})
    }
)

// reducers.ts
case SORT_RESULTS:
    let results = state.swapi_data.results;
    // title is heading of a table column (e.g. 'name', 'weight', etc)
    const title = action.payload;
    
    // sorts array with persons (objects)
    results.sort((a: any, b: any) => {
        return (a[title] > b[title]) ? 1 : ((b[title] > a[title]) ? -1 : 0)
    })

    // as in example with FETCH_DATA reducers it's doing the same job - returns new state object
    return {
        ...state,
        swapi_data: { 
            ...state.swapi_data,
            results: results,
        },
    }
1 Answers

Array Sort Mutates

If you mutate there is no change detected since the reference is the same. But sort also returns itself so you can add this code. The spread operator makes a copy and there for changes the reference meaning that your changes will be detected.

const sortedResults = results.sort((a: any, b: any) => {
  return (a[title] > b[title]) ? 1 : ((b[title] > a[title]) ? -1 : 0)
})

return {
        ...state,
        swapi_data: { 
            ...state.swapi_data,
            results: [...sortedResults],
        },
    }
Related