Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a modern React context for identity in the app #30098

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

renchap
Copy link
Sponsor Member

@renchap renchap commented Apr 28, 2024

This removes the last usage of the old and deprecated React context API (which will be removed from React 19, and outputs deprecation warnings in React 18.3).

Modern context can be used through contextType in class components, but it makes them not explicit when consumed (it would have been this.context.me, not this.context.identity.me).

I preferred to switch to injecting an identity prop using a wrapper component inspired by withOptionalRouter, so consuming identity is explicit (this.props.identity).

This removes the last usage of the old and deprecated React context API (which will be removed from React 19, and outputs deprecation warnings in React 18.3).

Modern context can be used through `contextType` in class components, but it makes them not explicit when consumed (it would have been `this.context.me`, not `this.context.identity.me`).

I preferred to switch to injecting an `identity` prop using a wrapper component inspired by `withOptionalRouter`, so consuming identity is explicit (`this.props.identity`).
@renchap renchap added refactoring Improving code quality javascript Pull requests that update Javascript code labels Apr 28, 2024
@renchap renchap requested a review from ClearlyClaire May 2, 2024 21:07
Comment on lines +46 to +74
/* Injects an `identity` props into the wrapped component to be able to use the new context in class components */
export function withIdentity<
ComponentType extends React.ComponentType<IdentityProps>,
>(Component: ComponentType) {
const displayName = `withIdentity(${Component.displayName ?? Component.name})`;
const C = (props: React.ComponentProps<ComponentType>) => {
const { wrappedComponentRef, ...remainingProps } = props;

return (
<IdentityContext.Consumer>
{(context) => {
return (
// @ts-expect-error - Dynamic covariant generic components are tough to type.
<Component
{...remainingProps}
identity={context}
ref={wrappedComponentRef}
/>
);
}}
</IdentityContext.Consumer>
);
};

C.displayName = displayName;
C.WrappedComponent = Component;

return hoistStatics(C, Component);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there's a more idiomatic way to write those wrappers…

Copy link
Sponsor Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the complexity here comes from handling the refs & display name, I am not sure if this can be made simpler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
javascript Pull requests that update Javascript code refactoring Improving code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants