t is unstable in appDir
jessemartin opened this issue · comments
Jesse Martin commented
What version of this package are you using?
2.6.2
(appDir)
What operating system, Node.js, and npm version?
N/A (present in all)
What happened?
The t
function returned by the useTranslation
hook is not stable.
Consider this problematic usage scenario, for example:
const { t } = useTranslation();
const [message, setMessage] = useState('');
const updateMessage = useCallback((evt) => { setMessage(evt.target.value); }, []);
const [triggerPostMessage, { isError: isPostMessageFailedError }] = usePostMessageMutation();
const postMessage = () => triggerPostMessage(message);
// This effect shows an error message if the post message request failed.
// `showToast` and `isPostMessageFailedError` are stable -- their references do not change when the component re-renders.
// However, `t` is unstable. So, every time this component re-renders (say, as `message` state is being updated by the user typing), this useEffect runs again, resulting in an additional toast being shown if in the error state.
// If `t` were instead stable, the effect would run only on `isPostMessageFailedError` transitions. And one toast would be shown when a transition into the error state occurs.
// There are many ways to work around this problem, but doing so should not be needed. `t` should be stable unless there is a good reason for it not to be.
useEffect(() => {
if (isPostMessageFailedError) {
showToast(t('post_message_failed_error_message'));
}
}, [isPostMessageFailedError, showToast, t]);
return (
<>
<input onChange={updateMessage} value={message} />
<button onClick={postMessage}>{t('post_message_button_text')}</button>
</>
);
What did you expect to happen?
t
should be a stable reference. This way, hooks that depend on it do not change on every render.
Are you willing to submit a pull request to fix this bug?
Yes, time allowing
Jesse Martin commented
PR here.