withProjectsSpecified.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. import * as React from 'react';
  2. import isEqual from 'lodash/isEqual';
  3. import ProjectsStore from 'app/stores/projectsStore';
  4. import {Project} from 'app/types';
  5. import getDisplayName from 'app/utils/getDisplayName';
  6. type Props = {
  7. projects?: Project[];
  8. specificProjectSlugs?: string[];
  9. };
  10. type InjectedProjectsProps = {
  11. loadingProjects: boolean;
  12. } & Props;
  13. type State = {
  14. projects: Project[];
  15. loading: boolean;
  16. };
  17. /**
  18. * Higher order component that takes specificProjectSlugs and provides list of that projects from ProjectsStore
  19. */
  20. function withProjectsSpecified<P extends InjectedProjectsProps>(
  21. WrappedComponent: React.ComponentType<P>
  22. ) {
  23. class WithProjectsSpecified extends React.Component<
  24. Props & Omit<P, keyof InjectedProjectsProps>,
  25. State
  26. > {
  27. static displayName = `withProjectsSpecified(${getDisplayName(WrappedComponent)})`;
  28. state = ProjectsStore.getState(this.props.specificProjectSlugs);
  29. static getDerivedStateFromProps(nextProps: Readonly<Props>): State {
  30. return ProjectsStore.getState(nextProps.specificProjectSlugs);
  31. }
  32. componentWillUnmount() {
  33. this.unsubscribe();
  34. }
  35. unsubscribe = ProjectsStore.listen(() => {
  36. const storeState = ProjectsStore.getState(this.props.specificProjectSlugs);
  37. if (!isEqual(this.state, storeState)) {
  38. this.setState(storeState);
  39. }
  40. }, undefined);
  41. render() {
  42. return (
  43. <WrappedComponent
  44. {...(this.props as P)}
  45. projects={this.state.projects as Project[]}
  46. loadingProjects={this.state.loading}
  47. />
  48. );
  49. }
  50. }
  51. return WithProjectsSpecified;
  52. }
  53. export default withProjectsSpecified;