Skip to content

reactjs useState: select onChange triggers setState but component doesn’t re-render

I’m trying to sort an array of objects by property using a select dropdown in react.

the data is defined in the parent container using the useState() hook, and I’m passing an onSortChange function down to the child select component, DataSelector. The data are displayed as a list by another component, DataList. Minimum example below to demonstrate (minus imports for brevity):

  1. Parent container:
const ParentContainer = () => {

    const [data, setData] = useState([]);

    useEffect( () => {
        populateData();
    }, []);

    function populateData() {
        const dave = {first_name: 'David', last_name: 'Taylor',
                    age: 25, salary: 25000};
        
        const bob = {first_name: 'Robert', last_name: 'Bush',
                    age: 31, salary: 30000};

        const sue = {first_name: 'Susan', last_name: 'Harman',
                    age: 22, salary: 28000};

        setData([dave, bob, sue]) 
    };

    const onSortChange = function(property) {
        setData(data.sort(propertySort(property)));
    };

    // sort by object property value (works for strings or )
    const propertySort = (prop) => {
        return function(a, b) {
            return (a[prop] < b[prop]) ? -1 : (a[prop] > b[prop]) ? 1 : 0;
        };
    };

    return (
        <>
            <DataSelector onSortChange={onSortChange} />
            <DataList data={data}/>
        </> 
    );
};

2: DataSelector component

const DataSelector = ({onSortChange}) => {

    const handleChange = function(event) {
        onSortChange(event.target.value);
    }

    return (
        <select onChange={handleChange}>
            <option value="first_name">Name</option>
            <option value="age">Age</option>
            <option value="salary">Salary</option>
        </select>
    );
};

export default DataSelector;

When I change the select option, handleChange fires correctly and if I console.log “data” in the parent container it correctly returns the array sorted by the value passed from handleChange. However, the DataList component doesn’t re-render the list items.

Is there another step I need to take to have DataList re-render after data’s setState function is called?

Answer

I think you need to use spread operator in order to correctly update state

Try like below:-

setData([...data.sort(propertySort(property))]);