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

Remove defaultProps usages for functional components #7224

Open
wants to merge 39 commits into
base: master
Choose a base branch
from

Conversation

undeletable
Copy link
Contributor

@undeletable undeletable commented May 9, 2024

What does this PR do?

Starting from React 19, defaultProps for functional components is deprecated. Starting from React 18.3, the corresponding error is thrown for a functional component with defaultProps defined.

Changes in this PR:

  • replace defaultProps for functional components with default function parameters values;
  • use attrs method of styled-components to pass theme to styled components which might be outside of theme context (required per remove defaultProps from Grommet #6741 (comment));
  • add custom hook to obtain theme from context with fallback to default value;
  • configure eslint rule to not require defaultProps for functional components;
  • update snapshots.

Where should the reviewer start?

No specific place to start.

What testing has been done on this PR?

  • manual testing on storybook and real project using grommet;
  • tests run result:
Test Suites: 97 passed, 97 total
Tests:       1548 passed, 1548 total
Snapshots:   1777 passed, 1777 total

How should this be manually tested?

Use React 18.3+ in an app. Check that styles are applied correctly and no errors about defaultProps are thrown into console.

Do Jest tests follow these best practices?

  • screen is used for querying.
  • The correct query is used. (Refer to this list of queries)
  • asFragment() is used for snapshot testing.

Any background context you want to provide?

React 19 upgrade guide

What are the relevant issues?

#6741

Screenshots (if appropriate)

N/A.

Do the grommet docs need to be updated?

Just the internal ones (if any).

Should this PR be mentioned in the release notes?

Yes.

Is this change backwards compatible or is it a breaking change?

Changes are backwards compatible.

DCO Remediation Commit for Max Shepel <max@undeletable.name>

I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: cd9a5b7
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 14838be
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 1766eed
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: b5e5d26
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: f005071
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 9f56eca
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 019d28b
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 45f81b2
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: b1ca758
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: be3a510
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: a8ed76e
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: e329a7a
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: ccd1a6c
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 87adfd3
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 164ac90
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 3926bc9
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 1abbf1b
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: bc92022
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 50478dd
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 9e94bce
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 2911f33
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 780ede8
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 74b3e2b
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 58770f0
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 7d584c8
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: b36c664
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: bd1a606
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 86687bf
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 302564b
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 3772235

Signed-off-by: Max Shepel <max@undeletable.name>
@undeletable undeletable changed the title Remove defaultProps usages Remove defaultProps usages for functional components May 10, 2024
@taysea taysea added the PRty Biweekly PR reviews by grommet team with hoping of closing such PRs label May 10, 2024
@britt6612
Copy link
Collaborator

@undeletable Thank you for your contribution! We are in the process of looking at this just wanted to let you know!

Copy link
Collaborator

@jcfilben jcfilben left a comment

Choose a reason for hiding this comment

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

Thanks for working on this!

In the changes I saw that you are using the attrs method of styled-components to pass the theme. In the PR notes you referenced this comment #6741 (comment) as the reason for those changes. I think this comment was misinterpreting the original intent of removing defaultProps.

There is some confusing naming where we have defaultProps in the react sense and then we have defaultProps in Grommet that contains the base theme. I think #6741 (comment), misunderstood the issue and was thinking that we would remove the defaultProps that has the Grommet theme instead of removing the react defaultProps.

All this to say I don't think the comment is relevant for what we are trying to do here with removing the react defaultProps and we don't need to use the attrs method.

We did also test to confirm that the base theme is being passed through correctly to components that are not in a Grommet wrapper in react 18.3.0 without using attrs.

@jcfilben jcfilben removed the PRty Biweekly PR reviews by grommet team with hoping of closing such PRs label May 23, 2024
@undeletable
Copy link
Contributor Author

undeletable commented May 23, 2024

@jcfilben

There is some confusing naming where we have defaultProps in the react sense and then we have defaultProps in Grommet that contains the base theme.

Actually these two entities are connected: Grommet's defaultProps is used as prototype for components' defaultProps.

Another hint for me was that component snapshots are way too different without both React's defaultProps and attrs usages, and almost equivalent with attrs.

@undeletable
Copy link
Contributor Author

undeletable commented May 24, 2024

@jcfilben
As far as I see, there are two ways of using theme for components.

Way 1. Using inside the component function:

const Card = forwardRef(({ ...rest }, ref) => {
  const theme = useContext(ThemeContext) || defaultProps.theme;

  return (...);
});

Here, the case of using component outside of theme context is handled by using fallback vaue.No need to pass theme as default prop. I just externalized this logic in the custom hook.

Way 2. Using inside arguments of styled-components' template function:

const StyledMinute = styled.line.withConfig(styledComponentsConfig)`
  stroke-width: ${(props) => props.theme.clock.analog.minute.width};
  stroke: ${(props) =>
    normalizeColor(props.theme.clock.analog.minute.color, props.theme)};
  transition: stroke 1s ease-out;
`;

StyledMinute.defaultProps = {};
Object.setPrototypeOf(StyledMinute.defaultProps, defaultProps);

Here, the case of using component outside of theme context is handled by passing theme as default prop. So, if defaultProps is removed for such a component, we need another way to pass default theme as fallback. For such cases I'm using attrs(). In the most recent commit I just removed attrs() calls for the places where props.theme is not used.

Also, I've tried to remove all attrs() calls from my changes. As result, several test suites failed: this was caused by failed attempts to get properties of theme, which was not defined.

Please correct me if I'm wrong.

I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 6cc1019
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 429627c
I, Max Shepel <max@undeletable.name>, hereby add my Signed-off-by to this commit: 5c80f67

Signed-off-by: Max Shepel <max@undeletable.name>
@jcfilben
Copy link
Collaborator

Thanks for the explanation, and sorry for the confusion on my end. Yesterday my team and I had tested in storybook by removing the Grommet wrapper and attrs and was still seeing the styles coming through so I was thinking we were good. But I just ran the unit tests and I see what you are saying about the difference in styles. I also had missed that we are currently using react defaultProps at the end of each Styled components file.

StyledMinute.defaultProps = {};
Object.setPrototypeOf(StyledMinute.defaultProps, defaultProps);

I think the direction you've taken with attrs makes sense.

src/js/default-props.js Outdated Show resolved Hide resolved
Signed-off-by: Max Shepel <max@undeletable.name>
@jcfilben
Copy link
Collaborator

If you update your branch with the latest changes from the master branch, the chromatic check should pass

@undeletable
Copy link
Contributor Author

undeletable commented May 24, 2024

@jcfilben Thanks for the suggestion, but this branch is up-to-date with master, and chromatic is still failing. The error is 'Missing project token' - I believe that's because I haven't set up one for the fork.

@jcfilben
Copy link
Collaborator

Hmm you shouldn't need to set anything up on your end, the chromatic token should be accessible from grommet forks when they run on circleci. I'll look into what might be going wrong here

@jcfilben
Copy link
Collaborator

jcfilben commented May 24, 2024

I'm going to try and push a no-op commit to your PR to see if I can re-trigger the chromatic step on circleci

edit: locally when I pull down this PR I have some tests failing, so I didn't end up pushing anything up yet

@undeletable
Copy link
Contributor Author

undeletable commented May 25, 2024

@jcfilben

locally when I pull down this PR I have some tests failing

For me, some tests for Pagination are slowly running locally - both in master and my branch. I haven't checked yet what's causing the slowness.

@undeletable
Copy link
Contributor Author

undeletable commented May 25, 2024

@jcfilben
From what I see, there's a different CircleCI project used for the fork:
https://app.circleci.com/pipelines/github/grommet/grommet
https://app.circleci.com/pipelines/github/undeletable/grommet
I assume here's the cause:

By default, CircleCI does not pass secrets to builds from forked PRs for open source projects and hides four types of configuration data:

Environment variables set through the application.

Deployment keys and user keys.

Passphraseless private SSH keys you have added to CircleCI to access arbitrary hosts during a build.

AWS permissions and configuration files.

Forked PR builds of open source projects that require secrets will not run successfully on CircleCI until you enable this setting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants