Skip to content

Commit 97a79de

Browse files
authored
feat: add configurable selector hook (#97)
1 parent b1298ac commit 97a79de

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

docs/rules/useSelector-prefer-selectors.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,24 @@ If provided, validates the name of the selector functions against the RegExp pat
5050
```js
5151
// .eslintrc
5252
{
53-
"react-redux/mapStateToProps-prefer-selectors": ["error", { matching: "^get.*FromState$"}]
53+
"react-redux/useSelector-prefer-selectors": ["error", { matching: "^get.*FromState$"}]
5454
}
5555

5656
// container.js
5757
const propertyA = useSelector(getAFromState) // success
5858
const propertyB = useSelector(getB) // failure
5959
```
60+
61+
### `hook`
62+
63+
Sets the name of the `useSelector` function to target. The value can also be an array of strings. Defaults to `['useSelector', 'useAppSelector']`.
64+
65+
```js
66+
// .eslintrc
67+
{
68+
"react-redux/useSelector-prefer-selectors": ["error", { hook: 'useAppSelector' }]
69+
}
70+
71+
// container.js
72+
const property = useAppSelector(state => state.mydata) // failure
73+
```

lib/rules/useSelector-prefer-selectors.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1-
function isUseSelector(node) {
2-
return node.callee.name === 'useSelector';
1+
function isUseSelector(node, hookNames) {
2+
return hookNames.includes(node.callee.name);
33
}
44

55
function reportWrongName(context, node, functionName, matching) {
66
context.report({
7-
message: `useSelector selector "${functionName}" does not match "${matching}".`,
7+
message: `${node.callee.name} selector "${functionName}" does not match "${matching}".`,
88
node,
99
});
1010
}
1111

1212
function reportNoSelector(context, node) {
1313
context.report({
14-
message: 'useSelector should use a named selector function.',
14+
message: `${node.callee.name} should use a named selector function.`,
1515
node,
1616
});
1717
}
1818

1919
module.exports = function (context) {
2020
const config = context.options[0] || {};
21+
let hookNames = ['useSelector', 'useAppSelector'];
22+
23+
// Ensure hookNames is an array
24+
if (config.hook) {
25+
hookNames = Array.isArray(config.hook) ? config.hook : [config.hook];
26+
}
27+
2128
return {
2229
CallExpression(node) {
23-
if (!isUseSelector(node)) return;
30+
if (!isUseSelector(node, hookNames)) return;
2431
const selector = node.arguments && node.arguments[0];
2532
if (selector && (
2633
selector.type === 'ArrowFunctionExpression' ||

tests/lib/rules/useSelector-prefer-selectors.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ ruleTester.run('useSelector-prefer-selectors', rule, {
3131
matching: '^selector$',
3232
}],
3333
},
34+
{
35+
code: 'const property = useAppSelector(selector)',
36+
options: [{
37+
matching: '^selector$',
38+
hook: 'useAppSelector',
39+
}],
40+
},
3441
],
3542
invalid: [{
3643
code: 'const property = useSelector((state) => state.x)',
@@ -68,5 +75,14 @@ ruleTester.run('useSelector-prefer-selectors', rule, {
6875
errors: [{
6976
message: 'useSelector selector "selectorr" does not match "^selector$".',
7077
}],
78+
}, {
79+
code: 'const property = useAppSelector(selectorr)',
80+
options: [{
81+
matching: '^selector$',
82+
hook: ['useSelector', 'useAppSelector'],
83+
}],
84+
errors: [{
85+
message: 'useAppSelector selector "selectorr" does not match "^selector$".',
86+
}],
7187
}],
7288
});

0 commit comments

Comments
 (0)