Search code examples
reactjstypescriptgenericsreact-context

React context with generics


How can we use generics in React.CreateContext?

I had this:

interface Props {
}

export interface SearchContextProps {
  dtos: any[];
}

export const SearchContext = React.createContext<SearchContextProps>({
  dtos: []
});

const SearchPage: React.FunctionComponent<Props> = (props) => {
  const [dtos, setDtos] = React.useState<any[]>([]);

  const searchContext = {
    dtos: dtos
  };

  return (
    <SearchContext.Provider value={searchContext}>
      ...
    </SearchContext.Provider>
  );
}

export default SearchPage;

Now I want to use generics, so I would write something like:

interface Props<T> {
}

export interface SearchContextProps<T> {
  dtos: T[];
}

export const SearchContext = React.createContext<SearchContextProps<T>>({
  dtos: []
});

const SearchPage = <T extends object>(props: Props<T>) => {
  const [dtos, setDtos] = React.useState<T[]>([]);

  const searchContext = {
    dtos: dtos
  };

  return (
    <SearchContext.Provider value={searchContext}>
      ...
    </SearchContext.Provider>
  );
}

export default SearchPage;

but I am missing how can I get to work the line:

export const SearchContext = React.createContext<SearchContextProps<T>>({

how can I use generics here, how can I have access to T?

I tried to move context inside the component:

interface Props<T> {
}

export interface SearchContextProps<T> {
  dtos: T[];
}

const SearchPage = <T extends object>(props: Props<T>) => {
  const [dtos, setDtos] = React.useState<T[]>([]);

  const SearchContext = React.createContext<SearchContextProps<T>>({
    dtos: [],
  });

  const searchContext = {
    dtos: dtos,
  };

  return (
    <SearchContext.Provider value={searchContext}>
      ...
    </SearchContext.Provider>
  );

}

export default SearchPage;

but now I don't know how to export it.

Any help?


Solution

  • I ended up with:

    import * as React from 'react';
    
    interface Props<T> {}
    
    export interface SearchContextProps<T> {
      dtos: T[];
    }
    
    export const SearchContext = React.createContext<SearchContextProps<any>>({
      dtos: [],
    });
    
    const SearchPage = <T extends object>(props: React.PropsWithChildren<Props<T>>) => {
      const [dtos, setDtos] = React.useState<T[]>([]);
    
      const searchContext = {
        dtos: dtos,
      };
    
      return <SearchContext.Provider value={searchContext}>...</SearchContext.Provider>;
    };
    
    export default SearchPage;
    

    And the consumer

    const searchContext = React.useContext<SearchContextProps<Interfaces.FileDto>>(SearchContext)