I have react ponent which needs to consume a customized react hook from within the ponent.
However, this hook should only be called when a feature toggle is enabled. I understand this is sort of anti-pattern as it is against the rule of hooks here: .html
So my ponent file is roughly in this structure:
const someFeatureToggle = useSomeFeatureToggleHook(React);
const callBackMethod = ()=>{
// doing the logic
}
const someRef1 = React.useRef();
const someOtherRef = React.useRef();
...
There are lots of useState( ) here
return (
JSX
)
For the customized hook:
export default function myCustomizedHook(topics, messagesReceivedFn, subscriptionOptions = {}) {
if (!isValidTopics(topics)) {
throw new Error(`Topics arg is invalid - Arg ${JSON.stringify(topics)}`);
}
const [someSubTopics] = useState([topics].flat());
const context = useContext(SomeEventContext);
if (isUndefined(context)) {
throw new Error(`${customizedHook.name} must be used within SomeProvider`);
}
const { connectionStatus, connector } = context;
const isConnectorConnected = connector?.connected ?? false;
const isConnectorReconnecting = connector?.reconnecting ?? false;
const messageReceivedHandler = useCallback(
(receivedTopic, message) => {
if (subscribedTopics.some((topic) => matches(topic, receivedTopic))) {
messagesReceivedFn?.(receivedTopic, message);
}
},
[messagesReceivedFn, subscribedTopics]
);
useEffect(() => {
isConnectorConnected && connector?.on(CLIENT_EVENTS.MESSAGE, messageReceivedHandler);
return () => {
connector?.off(CLIENT_EVENTS.MESSAGE, messageReceivedHandler);
};
}, [messageReceivedHandler, connector, isConnectorConnected]);
useDeepCompareEffect(() => {
isConnectorConnected && connector.subscribe(subscribedTopics, subscriptionOptions);
return () => {
subscribedTopics && connector?.unsubscribe(subscribedTopics);
};
}, [connector, isConnectorConnected, subscribedTopics, subscriptionOptions]);
return { isConnected: isConnectorConnected, isReconnecting: isConnectorReconnecting, connectionStatus, subscribedTopics };
Now the error trace is like this:
Uncaught Error: Should have a queue. This is likely a bug in React. Please file an issue.
at updateReducer (react-dom.development.js:15255:15)
at updateState (react-dom.development.js:15671:12)
at Object.useState (react-dom.development.js:16472:18)
at useState (react.development.js:1533:23)
at customizedHook (customizedHook.js:28:38)
at ponentThatConsumeHook (ponentThatConsumeHook.js:67:99)
at renderWithHooks (react-dom.development.js:15015:20)
at updateFunctionComponent (react-dom.development.js:17386:22)
at beginWork (react-dom.development.js:19093:18)
at HTMLUnknownElement.callCallback (react-dom.development.js:3942:16)
and there is this warning from dev console in the browser:
Warning: React has detected a change in the order of Hooks called by myComponent. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks:
Previous render Next render
------------------------------------------------------
1. useRef useRef
2. useState useState
3. useEffect useEffect
4. useRef useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
line 28 of customizedHook is point to this line below:
const [someSubTopics] = useState([topics].flat());
This is how I consume the hook in the ponent:
const result = (!!featureToggles.Flag) && customHook(arg1, callbackMethod);
I am scratching my head here as I have no clue why this is happening, any thought or advice would be greatly appreciated !!!!
I have react ponent which needs to consume a customized react hook from within the ponent.
However, this hook should only be called when a feature toggle is enabled. I understand this is sort of anti-pattern as it is against the rule of hooks here: https://reactjs/docs/hooks-rules.html
So my ponent file is roughly in this structure:
const someFeatureToggle = useSomeFeatureToggleHook(React);
const callBackMethod = ()=>{
// doing the logic
}
const someRef1 = React.useRef();
const someOtherRef = React.useRef();
...
There are lots of useState( ) here
return (
JSX
)
For the customized hook:
export default function myCustomizedHook(topics, messagesReceivedFn, subscriptionOptions = {}) {
if (!isValidTopics(topics)) {
throw new Error(`Topics arg is invalid - Arg ${JSON.stringify(topics)}`);
}
const [someSubTopics] = useState([topics].flat());
const context = useContext(SomeEventContext);
if (isUndefined(context)) {
throw new Error(`${customizedHook.name} must be used within SomeProvider`);
}
const { connectionStatus, connector } = context;
const isConnectorConnected = connector?.connected ?? false;
const isConnectorReconnecting = connector?.reconnecting ?? false;
const messageReceivedHandler = useCallback(
(receivedTopic, message) => {
if (subscribedTopics.some((topic) => matches(topic, receivedTopic))) {
messagesReceivedFn?.(receivedTopic, message);
}
},
[messagesReceivedFn, subscribedTopics]
);
useEffect(() => {
isConnectorConnected && connector?.on(CLIENT_EVENTS.MESSAGE, messageReceivedHandler);
return () => {
connector?.off(CLIENT_EVENTS.MESSAGE, messageReceivedHandler);
};
}, [messageReceivedHandler, connector, isConnectorConnected]);
useDeepCompareEffect(() => {
isConnectorConnected && connector.subscribe(subscribedTopics, subscriptionOptions);
return () => {
subscribedTopics && connector?.unsubscribe(subscribedTopics);
};
}, [connector, isConnectorConnected, subscribedTopics, subscriptionOptions]);
return { isConnected: isConnectorConnected, isReconnecting: isConnectorReconnecting, connectionStatus, subscribedTopics };
Now the error trace is like this:
Uncaught Error: Should have a queue. This is likely a bug in React. Please file an issue.
at updateReducer (react-dom.development.js:15255:15)
at updateState (react-dom.development.js:15671:12)
at Object.useState (react-dom.development.js:16472:18)
at useState (react.development.js:1533:23)
at customizedHook (customizedHook.js:28:38)
at ponentThatConsumeHook (ponentThatConsumeHook.js:67:99)
at renderWithHooks (react-dom.development.js:15015:20)
at updateFunctionComponent (react-dom.development.js:17386:22)
at beginWork (react-dom.development.js:19093:18)
at HTMLUnknownElement.callCallback (react-dom.development.js:3942:16)
and there is this warning from dev console in the browser:
Warning: React has detected a change in the order of Hooks called by myComponent. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useRef useRef
2. useState useState
3. useEffect useEffect
4. useRef useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
line 28 of customizedHook is point to this line below:
const [someSubTopics] = useState([topics].flat());
This is how I consume the hook in the ponent:
const result = (!!featureToggles.Flag) && customHook(arg1, callbackMethod);
I am scratching my head here as I have no clue why this is happening, any thought or advice would be greatly appreciated !!!!
Share Improve this question edited Feb 22, 2022 at 3:19 Edward Sun asked Feb 22, 2022 at 3:09 Edward SunEdward Sun 531 silver badge6 bronze badges 1- Conditionally calling hooks is not “sort of an anti-pattern” as you describe it. It results (as you’ve discovered) in plain brokenness. Hooks 100% rely on the fact that they are never called conditionally. Mess around and find out, to paraphrase. – Adam Jenkins Commented Feb 22, 2022 at 3:46
1 Answer
Reset to default 7That's because you're calling hook inside a condition.
const result = (!!featureToggles.Flag) && customHook(arg1, callbackMethod);
is basically the same as
let result = false
if (!!featureToggles.Flag){
result = customHook(arg1, callbackMethod);
}
From React document:
Don’t call Hooks inside loops, conditions, or nested functions.
What you could do is to pass featureToggles
into your custom hook and do the check inside that instead.
Make sure your condition check is at the bottom of your hook, below every hook call.
// pass featureToggles here
export default function myCustomizedHook(featureToggles, topics, messagesReceivedFn, subscriptionOptions = {}) {
// your code here
useDeepCompareEffect(() => {
isConnectorConnected && connector.subscribe(subscribedTopics, subscriptionOptions);
return () => {
subscribedTopics && connector?.unsubscribe(subscribedTopics);
};
}, [connector, isConnectorConnected, subscribedTopics, subscriptionOptions]);
// make sure to do the check at the bottom, below every hook call
if (!!featureToggles.Flag) {
// handle this feature toggle
return null
}
return { isConnected: isConnectorConnected, isReconnecting: isConnectorReconnecting, connectionStatus, subscribedTopics };
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742339244a4425283.html
评论列表(0条)