@arthurgeron/eslint-plugin-react-usememo
Advanced tools
Comparing version 0.0.4 to 0.1.0
@@ -105,6 +105,9 @@ 'use strict'; | ||
"object-usememo-props": "Object literal should be wrapped in useMemo() or be static when used as a prop", | ||
"object-class-memo-props": "Object literal should com from state or be static when used as a prop", | ||
"object-usememo-deps": "Object literal should be wrapped in useMemo() or be static when used as a hook dependency", | ||
"array-usememo-props": "Array literal should be wrapped in useMemo() or be static when used as a prop", | ||
"array-class-memo-props": "Array literal should be from state and declared in state, constructor, getDerivedStateFromProps or statically when used as a prop", | ||
"array-usememo-deps": "Array literal should be wrapped in useMemo() or be static when used as a hook dependency", | ||
"instance-usememo-props": "Object instantiation should be wrapped in useMemo() or be static when used as a prop", | ||
"instance-class-memo-props": "Object instantiation should be done in state, constructor, getDerivedStateFromProps or statically when used as a prop", | ||
"instance-usememo-deps": "Object instantiation should be wrapped in useMemo() or be static when used as a hook dependency", | ||
@@ -114,4 +117,6 @@ "jsx-usememo-props": "JSX should be wrapped in useMemo() when used as a prop", | ||
"function-usecallback-props": "Function definition should be wrapped in useCallback() or be static when used as a prop", | ||
"function-class-props": "Function definition should declared as a class property or statically when used as a prop", | ||
"function-usecallback-deps": "Function definition should be wrapped in useCallback() or be static when used as a hook dependency", | ||
"unknown-usememo-props": "Unknown value may need to be wrapped in useMemo() when used as a prop", | ||
"unknown-class-memo-props": "Unknown value should be declared in state, constructor, getDerivedStateFromProps or statically when used as a prop", | ||
"unknown-usememo-deps": "Unknown value may need to be wrapped in useMemo() when used as a hook dependency", | ||
@@ -240,2 +245,3 @@ "usememo-const": "useMemo/useCallback return value should be assigned to a const to prevent reassignment" | ||
create: function (context) { | ||
var isClass = false; | ||
function report(node, messageId) { | ||
@@ -260,12 +266,12 @@ context.report({ node: node, messageId: messageId }); | ||
case MemoStatus.UnmemoizedObject: | ||
report(node, "object-usememo-props"); | ||
report(node, isClass ? "object-class-memo-props" : "object-usememo-props"); | ||
return; | ||
case MemoStatus.UnmemoizedArray: | ||
report(node, "array-usememo-props"); | ||
report(node, isClass ? "array-class-memo-props" : "array-usememo-props"); | ||
return; | ||
case MemoStatus.UnmemoizedNew: | ||
report(node, "instance-usememo-props"); | ||
report(node, isClass ? "instance-class-memo-props" : "instance-usememo-props"); | ||
return; | ||
case MemoStatus.UnmemoizedFunction: | ||
report(node, "function-usecallback-props"); | ||
report(node, isClass ? 'instance-class-memo-props' : "function-usecallback-props"); | ||
return; | ||
@@ -275,6 +281,9 @@ case MemoStatus.UnmemoizedFunctionCall: | ||
if ((_b = (_a = context.options) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.strict) { | ||
report(node, "unknown-usememo-props"); | ||
report(node, isClass ? "unknown-class-memo-props" : "unknown-usememo-props"); | ||
} | ||
return; | ||
case MemoStatus.UnmemoizedJSX: | ||
if (isClass) { | ||
return; | ||
} | ||
report(node, "jsx-usememo-props"); | ||
@@ -297,2 +306,5 @@ return; | ||
}, | ||
ClassDeclaration: function () { | ||
isClass = true; | ||
}, | ||
CallExpression: function (node) { | ||
@@ -352,2 +364,3 @@ var _a, _b; | ||
create: function (context) { | ||
var isClass = false; | ||
function report(node, messageId) { | ||
@@ -357,6 +370,9 @@ context.report({ node: node, messageId: messageId }); | ||
return { | ||
ClassDeclaration: function () { | ||
isClass = true; | ||
}, | ||
JSXElement: function (node) { | ||
var _a, _b; | ||
var _c = node, children = _c.children, openingElement = _c.openingElement; | ||
if (!isComplexComponent(openingElement)) | ||
if (isClass || !isComplexComponent(openingElement)) | ||
return; | ||
@@ -363,0 +379,0 @@ for (var _i = 0, children_1 = children; _i < children_1.length; _i++) { |
{ | ||
"name": "@arthurgeron/eslint-plugin-react-usememo", | ||
"version": "0.0.4", | ||
"version": "0.1.0", | ||
"description": "", | ||
@@ -13,2 +13,4 @@ "main": "dist/index.js", | ||
"devDependencies": { | ||
"@commitlint/cli": "17.0.3", | ||
"@commitlint/config-conventional": "17.0.3", | ||
"@jest/types": "28.1.3", | ||
@@ -32,2 +34,3 @@ "@rollup/plugin-node-resolve": "13.3.0", | ||
"build": "rm -rf dist && rollup -c", | ||
"prepare": "husky install", | ||
"prepublish:public": "npm run build", | ||
@@ -34,0 +37,0 @@ "publish:public": "npm publish --access public", |
@@ -53,9 +53,44 @@ # eslint-plugin-react-usememo | ||
function renderItem({ item }) { | ||
return <Text>item.name</Text>; | ||
return (<Text>item.name</Text>); | ||
} | ||
// Data isn't redeclared each ender but `[]` is | ||
<FlatList renderItem={renderItem} data={data ?? []} /> | ||
return (<FlatList renderItem={renderItem} data={data ?? []} />); | ||
} | ||
``` | ||
## **Incorrect** (class component) | ||
```JavaScript | ||
class Component() { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
data: undefined, | ||
propDrivenData: props., | ||
}; | ||
} | ||
// This will NOT be redeclared each render | ||
getItemName(item) { | ||
return item.name; | ||
} | ||
render() { | ||
// This function will be redeclared each render | ||
function renderItem({ item }) { | ||
return (<Text>{this.getItemName(item)}</Text>); | ||
} | ||
// Data isn't redeclared each ender but [] is | ||
// Extradata has a exponential complexity (will iterate the entire array for each render, could render once or several times in a second) | ||
// Outcome will be that any new render on this component will cause the entire FlatList to render again, including children components, even if the data hasn't changed. | ||
return (<FlatList | ||
renderItem={renderItem} | ||
data={data ?? []} | ||
extraData={dataArray.filter(id => !!id)} | ||
/>); | ||
} | ||
} | ||
``` | ||
In the previous example there are two issues, a function and a object that will be dynamically redeclared each time the component renders, which will cause FlatList to keep re-rendering even when the input data hasn't changed. | ||
@@ -76,5 +111,43 @@ | ||
// Will only render again if data changes | ||
return (<FlatList renderItem={renderItem} data={data ?? EMPTY_ARRAY} />); | ||
} | ||
``` | ||
## **Correct** (class component) | ||
```JavaScript | ||
// Static therefore is only declared once | ||
const EMPTY_ARRAY = []; | ||
class Component() { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
data: undefined, | ||
propDrivenData: props.dataArray.filter(id => !!id), | ||
}; | ||
} | ||
// Properly regenerate state driven data only when props change instead of during each render | ||
static getDerivedStateFromProps(props) { | ||
if (props.propDrivenData !== this.props.propDrivenData) { | ||
return { | ||
propDrivenData: props.dataArray.filter(id => !!id), | ||
}; | ||
} | ||
return null; | ||
} | ||
<FlatList renderItem={renderItem} data={data ?? EMPTY_ARRAY} /> | ||
// Will be declared only once. | ||
getItemName({item}) { | ||
const { data } = this.state; | ||
const dataLength = data ? data.length : 0; | ||
return (<Text>{item.name} {dataLength}</Text>); | ||
} | ||
render() { | ||
const { data } = this.state; | ||
// Will only cause a new render if data changes | ||
return (<FlatList renderItem={this.renderItem} data={data ?? EMPTY_ARRAY} />); | ||
} | ||
} | ||
@@ -92,6 +165,6 @@ ``` | ||
const renderItem = useCallback(({ item }) => { | ||
return <Text>{isEditing ? 'item.name' : 'Editing'}</Text>; | ||
return (<Text>{isEditing ? 'item.name' : 'Editing'}</Text>); | ||
}, [isEditing]); | ||
<FlatList renderItem={renderItem} data={data ?? EMPTY_ARRAY} /> | ||
return (<FlatList renderItem={renderItem} data={data ?? EMPTY_ARRAY} />); | ||
} | ||
@@ -107,4 +180,3 @@ ``` | ||
export default function Component() { | ||
<Text>This is a component</Text> | ||
return (<Text>This is a component</Text>); | ||
} | ||
@@ -116,4 +188,3 @@ ``` | ||
export default memo(function Component() { | ||
<Text>This is a component</Text> | ||
return (<Text>This is a component</Text>); | ||
}); | ||
@@ -134,7 +205,7 @@ ``` | ||
<View> | ||
return (<View> | ||
<> | ||
<OtherComponent /> | ||
</> | ||
</View> | ||
</View>); | ||
} | ||
@@ -146,8 +217,8 @@ ``` | ||
function Component() { | ||
const children = useMemo(() => (<OtherComponent />), []); | ||
<View> | ||
return (<View> | ||
{children} | ||
</View> | ||
</View>); | ||
} | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
26318
407
218
16