5

My use state variable, query, inside of the function isExternalFilterPresent never updates. I'm perplexed because the first console.log of query updates with each change of query. I think this is because I'm not quite understand the implementation of hooks.

let gridApi: GridApi | null = null;

const HouseholdTable = ({accountsData, aggregateEntityTable: {aggregateEntity, columnDefs}}: OwnProps & StateProps) => {

  const [isDeepDiveOpen, setIsDeepDiveOpen] = useState(false);
  const [query, setQuery] = useState('');

  useEffect(() => {
    gridApi && gridApi.onFilterChanged();
  }, [query]);

  if (accountsData) {

    const onGridReady = ({api}: GridReadyEvent) => {
      api.sizeColumnsToFit();
      gridApi = api;
    };

    const aggData = accountsData.aggregations[aggregateEntity];

    console.log(query); // This updates when query changes
    const isExternalFilterPresent = (): boolean => {
      console.log(query); // This never updates
      return !!query; 
    };

    const doesExternalFilterPass = (rowNode: RowNode): boolean => {
      // console.log('doesExternalFilterPass');
      return true;
    };

    return (
      <>
        <HouseholdsToolbar aggData={aggData}
          isDeepDiveOpen={isDeepDiveOpen}
          onDeepDiveToggleClick={setIsDeepDiveOpen}
          onQueryChange={setQuery}
        />
        <AgGridReact rowData={[]}
          columnDefs={[]}
          gridOptions={{
            headerHeight: 70,
            suppressFieldDotNotation: true,
            suppressHorizontalScroll: false,
            onGridReady,
            isExternalFilterPresent,
            doesExternalFilterPass
          }}
        />
      </>
    );
  } else {
    // handle loading
    return (<div>loading</div>);
  }
};

const mapStateToProps = (state: StoreState): StateProps => {
  const {faStore: {accountsData}} = state;
  return {
    accountsData,
    aggregateEntityTable: aggregateEntityTableDummyConfig
  };
};

export default connect(mapStateToProps)(HouseholdTable);

export const aggregateEntityTableDummyConfig: AggregateEntityTable = {
  aggregateEntity: 'FOO',
  columnDefs: []
};

EDIT: Updated with the entire component.

Jstuff
  • 1,266
  • 2
  • 16
  • 27
  • can you add the whole component please? – Atin Singh Oct 25 '19 at 15:17
  • @AtinSingh updated with the entire component. – Jstuff Oct 25 '19 at 15:37
  • 1
    I put together a code pen with a simplified (just a dummy AgGrid component) example that works with hooks but I'm unable to see what is wrong. Maybe it will still help you or someone else figure it out [working codepen](https://codepen.io/WillWillman/pen/yLLXBwX) cheers! – Willman.Codes Oct 25 '19 at 15:52

1 Answers1

9

It is not a problem with hooks. It looks like on the first rendering AgGridReact stores the reference to a function that you pass to isExternalFilterPresent and then never changes this reference on re-renders. To be more clear, AgGridReact stores the first 'version' of isExternalFilterPresent and never updates it. To fix your problem, you need to store the value of your filter in useRef hook.

React doc says:

The useRef() Hook isn’t just for DOM refs. The “ref” object is a generic container whose current property is mutable and can hold any value, similar to an instance property on a class.

So you might think about useRef like about property in the class.

Here what you have to do:

const query = useRef(null);

const setQuery = (value) => {
  query.current = value;
  gridApi && gridApi.onFilterChanged();
}

const isExternalFilterPresent = (): boolean => {
  console.log(query.current); // Now it changes
  return !!query.current; 
};

Here an example on codesandbox

Andrii Golubenko
  • 4,879
  • 1
  • 22
  • 27
  • 2
    After more investigation, I see that the callback `isExternalFilterPresent` never updates, meaning that the value for query never updates. Using a ref is the way around this. Thanks for the help! – Jstuff Oct 25 '19 at 16:56