How can you efficiently update the fill of GeoJson polygons in MapboxGL?

I’m building an application that will render a map with a large GeoJSON set (around 3MB). The map is a choropleth, and the different GeoJSON polygons are meant to be colored differently depending on the data that they “contain.”

The problem I’m running into is that I’m unsure how to separate the GeoJSON (e.g. polygon data) from the actual data. Let’s say we set the data like this (or as Mapbox recommends, just via the URL to a data source):

const { data } = await axios.post(sourceUrl, settings);
map.current.addSource("states", {
  type: "geojson",
  data,
}

The underlying data in this map will need to update frequently with user interaction. However, right now the GeoJSON contains both the data for the polygons (coordinates) and the properties (the data itself).

For instance, the user might click a checkbox, or type in a search parameter. This currently makes a GET to our DB, which runs a query and returns the new data. We could return a new GeoJSON object with this data added inside of it and call a .getSource("source").setData(newData) will all of the new GeoJSON, but that would be terribly inefficient. The polygons aren’t changing, only the data they contain is.

I’ve looked into data-driven styling, but that doesn’t appear to be what I need either. Our underlying data set for the map is far too large to be crammed into a single GeoJSON layer, we can’t transfer hundreds of MBs over the network in order to apply data-driven styles on the client.

How can we render GeoJSON polygons to the map just once, and then update their fill colors depending on how a different data set is changed?