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

Change eslint configuration and fix resulting issues #4423

Merged
merged 13 commits into from
Dec 11, 2019
Merged

Change eslint configuration and fix resulting issues #4423

merged 13 commits into from
Dec 11, 2019

Conversation

arikfr
Copy link
Member

@arikfr arikfr commented Dec 5, 2019

What type of PR is this?

  • Other

Description

We were using airbnb's eslint settings, which at the time seemed like a good setting to use. The problem was that they were outdated and had a mix of styling rules (like which type of quotes to use or line length) and actual linting rules. We are also using Prettier to format our code and it has some conflicting style choices with the eslint rules.

While this can be resolved by using prettier-eslint, it's less recommended these days. I decided to find us better defaults that will be more about linting and les about style. In search of a better default, I decided to pick create-react-app's eslint configuration, as it's very likely we will adopt create-react-app once we get rid of Angular..js in our codebase.

(later I found eslint-config-prettier, which just disables the conflicting rules, but already invested the work in doing the switch)

This resulted in a few new rules that found some issues in our codebase:

  • Issues with dependencies provided to React Hooks - 0d4730d. This was fixed with eslint --fix. @gabrieldutra @kravets-levko can you make sure it all makes sense?
  • Mixed operators issues- cf6d780. I actually found it confusing myself.
  • The rule that checks useCallback's dependencies found an actual bug in our code:
    fd7d19a.
  • 6c676f9: another bug found by a lint rule.

I also added Prettier config and removed some dead code, but I will apply Prettier on the codebase in a separate PR to make it easier the code changes in this PR.

There were 3 issues that I wasn't sure how to fix, although they did seem like an actual issue:

client/app/components/QuerySelector.jsx
  67:23  warning  Assignments to the 'isStaleSearch' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect  react-hooks/exhaustive-deps

client/app/lib/hooks/useQueryResult.js
  27:21  warning  Assignments to the 'isCancelled' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect  react-hooks/exhaustive-deps

client/app/lib/hooks/useSearchResults.js
  29:27  warning  Assignments to the 'isDestroyed' variable from inside React Hook useEffect will be lost after each render. To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property. Otherwise, you can move this variable directly inside useEffect  react-hooks/exhaustive-deps

@arikfr arikfr added Frontend Frontend: React Frontend codebase migration to React labels Dec 5, 2019
@@ -27,7 +27,7 @@ export default function FavoritesDropdown({ fetch, urlTemplate }) {
}, [fetch]);

// fetch items on init
useEffect(() => fetchItems(false), []);
useEffect(() => fetchItems(false), [fetchItems]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are you sure this should be fixed? According to comment, it should fetch items only once, but with this fix it will re-load items each time fetchItems changed

Copy link
Member Author

Choose a reason for hiding this comment

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

Not sure at all - it's part of the automatic fixes.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm also not sure how it supposed to work. Maybe @gabrieldutra will help 🤔

Copy link
Member

Choose a reason for hiding this comment

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

I'm testing these eslint changes, it's indeed a case where it makes it mandatory. In this specific case I think it's ok to keep the dependency as fetchItems should only change if the fetch prop change (in this case I think we do want the items to be loaded again).

Though from a quick search there are discussions around this (like this one). Just need to confirm if there's a more correct React way (they do mention useMemo, but imo that only applies to when you don't have a Promise to solve).

A side note I just noticed: I'd avoid the () => executeFunction() for useEffect as the return value is used for cleaning. Anyway, I'll check other replacements to see if they can be problematic.

@@ -34,7 +34,7 @@ function useGrantees(url) {

const addPermission = useCallback((userId, accessType = 'modify') => $http.post(
url, { access_type: accessType, user_id: userId },
).catch(() => notification.error('Could not grant permission to the user'), [url]));
).catch(() => notification.error('Could not grant permission to the user')), [url]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

@@ -77,7 +77,7 @@ function UserSelect({ onSelect, shouldShowUser }) {
useEffect(() => {
setLoadingUsers(true);
debouncedSearchUsers(searchTerm);
}, [searchTerm]);
}, [debouncedSearchUsers, searchTerm]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably it should be replaced with use-debounced 🤔 But let's keep as is for now

@@ -58,7 +58,7 @@ export default function Renderer({ data, options, onOptionsChange }) {
options, // detect changes for all options except bounds, but pass them all!
);
}
}, [map, geoJson, data, optionsWithoutBounds]);
}, [map, geoJson, data, optionsWithoutBounds, options]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This change will cause performance issues - see comment above

Copy link
Collaborator

Choose a reason for hiding this comment

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

@gabrieldutra Can you please address this in #4425 as well?

Copy link
Member

Choose a reason for hiding this comment

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

Done 👍

@@ -16,7 +16,7 @@ function generateRowKeyPrefix() {

export default function Renderer({ data, options }) {
const funnelData = useMemo(() => prepareData(data.rows, options), [data, options]);
const rowKeyPrefix = useMemo(() => generateRowKeyPrefix(), [funnelData]);
const rowKeyPrefix = useMemo(() => generateRowKeyPrefix(), []);
Copy link
Collaborator

Choose a reason for hiding this comment

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

rowKeyPrefix should be generated every time funnelData changes to ensure that Ant Table will properly update rows

Copy link
Member

Choose a reason for hiding this comment

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

I was checking, useEffect doesn't require dependencies to be used (useMemo does), so the options: 1 - Move it to useEffect and useState for the rowKeyPrefix; 2 - eslint-disable;

I think 2 is the quick one ^^

Copy link
Collaborator

Choose a reason for hiding this comment

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

1 is more confusing (IMO) - this use case is perfect for useMemo, but not as obvious with useState + useEffect. So I'm for 2, or I can try to find another (?) solution.

"eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^2.1.1",
Copy link
Member

Choose a reason for hiding this comment

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

Isn't this necessary to load eslint with webpack? I started getting an error for it (webpack.config.js points to eslint-loader)

Copy link
Member

Choose a reason for hiding this comment

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

Just confirming that, I'll open a PR with some updates, if you want I can do that along with it.

Copy link
Member Author

Choose a reason for hiding this comment

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

My bad... I just removed all the previous *eslint* dependencies 😬

@gabrieldutra
Copy link
Member

@kravets-levko regarding the other 3 issues Arik mentioned (the let variables to avoid stale results), from what I understood it's meant to be like that, but has an issue ever happened with the nonexistence of that? I mean, do we really need that, or, isn't the unsubscribe function in useEffect enough?

@arikfr
Copy link
Member Author

arikfr commented Dec 8, 2019

@gabrieldutra I'm not sure if an issue will be noticeable or easy to reproduce. But reading the error + the code it does seem like the code that uses these let variables will not work.

@kravets-levko
Copy link
Collaborator

client/app/lib/hooks/useQueryResult.js
27:21 warning Assignments to the 'isCancelled' variable from inside React Hook useEffect will be lost after each render.

isCancelled should be moved to useEffect

client/app/lib/hooks/useSearchResults.js
29:27 warning Assignments to the 'isDestroyed' variable from inside React Hook useEffect will be lost after each render.

isDestroyed should be replaced with useRef

client/app/components/QuerySelector.jsx
67:23 warning Assignments to the 'isStaleSearch' variable from inside React Hook useEffect will be lost after each render

The perfect solution is to use useSearchResults (with fix mentioned above). Also, I'm not sure if that code should use useRef instead of let 🤔

Copy link
Member

@gabrieldutra gabrieldutra left a comment

Choose a reason for hiding this comment

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

Also, I'm not sure if that code should use useRef instead of let

Seemed the best option to solve this 👍.

BTW, I didn't see a reason to refactor that to use useSearchResults, so I just applied the same useRef fix as it was quicker. I realized that the useRef in that file causes issues, so moved to use useSearchResults.

@@ -58,7 +58,7 @@ export default function Renderer({ data, options, onOptionsChange }) {
options, // detect changes for all options except bounds, but pass them all!
);
}
}, [map, geoJson, data, optionsWithoutBounds]);
}, [map, geoJson, data, optionsWithoutBounds, options]);
Copy link
Member

Choose a reason for hiding this comment

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

Done 👍

@arikfr
Copy link
Member Author

arikfr commented Dec 10, 2019

@kravets-levko good to go?

Copy link
Collaborator

@kravets-levko kravets-levko left a comment

Choose a reason for hiding this comment

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

Seems everything is fine 👍

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

Successfully merging this pull request may close these issues.

3 participants