Why do I get maximum update depth exceeded for rendered screen? - reactjs

I get an error for one component that Maximum update depth exceeded, I tried to figure out what cause the issue and I fail. Can You please look at the console comment and the code and suggest where shall I search for problem solving ?
export const LineAlertsScreen = () => {
const { useTranslationFunc } = useTranslationFacade();
const { lineAlertsData, getLineAlertsData } =
useContext(LineDetailsContext);
const { handlePushToProperLocationDependingOnAlertValues } =
useContext(AlertsContext);
const { lineId } = useParams<RouterParamsModel>();
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up('md'));
useEffect(() => {
if (lineId) {
getLineAlertsData(lineId);
}
}, [lineId]);
const dateTranslation = useTranslationFunc('Data');
const lineTranslation = useTranslationFunc('Linia');
const typeTranslation = useTranslationFunc('Typ');
const lineKmTranslation = useTranslationFunc('Kilometr');
const descriptionTranslation = useTranslationFunc('Opis');
return (
<div>
<LinesGlobalToolbar />
<StyledAlertsContentWrapper>
{matches && <SideNavigationPanelLines />}
<StyledBackgroundGreyDiv>
<StyledBackgroundContainerDiv>
<LineHeader lineId={lineId} />
<StyledBackgroundContentContainerDiv>
<StyledHeaderDiv>
{useTranslationFunc('Lista alertów')}
</StyledHeaderDiv>
<AlertList
columns={columns}
data={lineAlertsData ?? []}
onRowClick={
handlePushToProperLocationDependingOnAlertValues
}
/>
</StyledBackgroundContentContainerDiv>
</StyledBackgroundContainerDiv>
</StyledBackgroundGreyDiv>
</StyledAlertsContentWrapper>
{!matches && <LinesBottomNavigationMobile />}
</div>
);
};

Related

Why I can not get ref as expected

I have React App which detects hovered elements to perform the action of getting images. I would like to use ref to assure catching hover only from a specific areas of the page.
Working simplified version is like this:
const Form = props => {
const { fetchHints, hints, clearHints, fetchImages } = props;
const refSelect = React.useRef();
function getImages(e) {
if (e.key === "Enter") {
const withHover = getHovered(refSelect.current);
if (withHover) {
const className = withHover.className;
if (className.includes("option")) {
fetchImages(withHover.textContent);
history.push("./images");
}
}
}
}
return (
<div onKeyDown={debouncedGetImages}>
<div ref={refSelect}>
<SelectSection hints={hints} getValues={getValues} changeHandler={fetchImages} />
</div>
</div>
);
};
However, it is obvious that <div ref={refSelect}> only role is to be a point where the ref is anchored and it is useless besides. So, I tried to anchor ref just on SelectionSection:
<SelectSection hints={hints} getValues={getValues} changeHandler={fetchImages} ref={refSelect} />
while SelectionSection is as follows (any type is for initial simplicity):
const SelectSection = React.forwardRef((props: Props & RouteComponentProps, ref: any) => {
const { hints, getValues, changeHandler } = props;
const history = useHistory();
const path = props.match.path;
return hints?.length && path === "/" ? (
<Select
ref={ref}
className="select-top"
id="BigSelect"
value={getValues}
isClearable={true}
menuIsOpen={true}
onChange={selectValue => {
changeHandler(selectValue.value);
history.push("./images");
}}
options={hints}
/>
) : null;
});
export default withRouter(SelectSection);
The problem is that in this case refSelect is always undefined. What is wrong with this code?

React Component is rerendering, even though it does not depend on the state

In my React code I have to use a legacy component, which makes a setup api call when it is first rendered. The component has a custom completion/cancelation event which I use to trigger a State update. The current Code looks like this:
export const useOneTimePassword = (
headline = "OTP anfordern",
id = "opt",
type = "sms",
businessProcess = "otp-process"
): UseOneTimePasswordReturn => {
const [otpCode, setOtpCode] = useState<undefined | string>();
const [isOtpCancelled, setIsOtpCancelled] = useState<boolean>(false);
const openOtp = () => {
const otp = document.querySelector(`otp-component#${id}`) as OtpElement;
otp.open();
};
const OtpComponent: FC = () => (
<Otp
headline={headline}
id={id}
type={type}
businessProcess={businessProcess}
setIsOtpCancelled={setIsOtpCancelled}
setOtpCode={setOtpCode}
/>
);
return {
otpCode,
isOtpCancelled,
openOtp,
OtpComponent,
removeOtp: () => {
setOtpCode(undefined);
},
};
};
and for the Component it looks like this:
const Otp: React.FC<OtpProps> = ({
headline,
businessProcess,
type,
id,
setOtpCode,
setIsOtpCancelled,
}) => {
function onOtpResponse(e: CompletedEvent) {
if (e.detail.otpCode) {
setOtpCode(e.detail.otpCode);
setIsOtpCancelled(false);
} else {
setIsOtpCancelled(true);
}
}
const ref = useRef();
useEffect(() => {
//#ts-ignore
if (ref.current) ref.current.addEventListener("completed", onOtpResponse);
}, []);
return (
<otp-component
ref={ref}
headline={headline}
id={id}
type={type}
business-process={businessProcess}
/>
);
};
export default Otp;
What I do not understand is that state changes in otpCode aswell as isOtpCancelled cause a rerender of the OtpComponent

How to resolve this reference error : Audio is not defined

Problem
I'm trying to play some audio files in some specific situations.
e.g)
When users access to login page, the audio plays 'Please enter your phone number'
when an error message alert comes up, audio file is played such as 'your phone number has been already registered'
So far, the audio files are played successfully when you access some pages, but I got the reference error in the image after I added two lines of code below in the root component (app.tsx)
import {kioskAudio} from '../src/common/utils/kioskAudio';
const {playAudio, stopAudio} = kioskAudio();
What I've tried to resolve this issue
First try:
I imported 'kioskAudio' method into KioskAlertError component directly. But I got the same reference error.
Second try:
So I thought, 'Then should I import the 'kioskAudio' method to the root component(app.tsx) and deliver the props(playAudio, stopAudio) to the component like this :
<KioskAlertError playAudio={playAudio} stopAudio={stopAudio} />
But I still got the reference error. How can I resolve this issue?
Source Code
app.tsx
import KioskAlert, {IKioskAlertProps} from './component/KioskAlert';
import KioskAlertError from './component/KioskAlertError';
import {kioskAudio} from '../src/common/utils/kioskAudio';
export default function CustomApp({Component, pageProps}) {
const router = useRouter();
const [shouldStartRender, setShouldStartRender] = useState(false);
const [kioskAlertInfo, setKioskAlertInfo] = useState({isShow: false, onOK: null} as IKioskAlertProps);
const {playAudio, stopAudio} = kioskAudio();
useEffect(() => {
setShouldStartRender(true);
}, [router]);
return (
<>
<KioskAlertContext.Provider
value={{
kioskAlertState: kioskAlertInfo,
openKioskAlert: openKioskAlert,
closeKioskAlert: closeKioskAlert,
}}
>
<SWRConfig
value={{
refreshInterval: 0,
revalidateOnReconnect: true,
revalidateOnFocus: true,
onErrorRetry: (error, key, config, revalidate, {retryCount}) => {
if (error.response?.status === 401) {
localStorage.removeItem('accessToken');
return;
}
if (retryCount >= 5) return;
setTimeout(() => {
revalidate({retryCount});
}, 5000);
},
}}
>
{shouldStartRender ? (
<DomRouter>
<DomRoutes>
<DomRoute path="/home/home.html" element={<Home />} />
<DomRoute path="/home/clause.html" element={<Clause />} />
<DomRoute path="/home/loginPhone.html" element={<LoginPhone />} />
<DomRoute path="/home/loginPin.html" element={<LoginPin />} />
<DomRoute path="/home/signUp-phone.html" element={<SignUpPhone />} />
<DomRoute path="/home/signUp-authCode.html" element={<SignUpAuthCode />} />
<DomRoute path="/home/signUp-pin.html" element={<SignUpPin />} />
<DomRoute path="/home/CheckUserByPin.html" element={<CheckUserByPin />} />
</DomRoutes>
</DomRouter>
) : null}
<KioskAlertError playAudio={playAudio} stopAudio={stopAudio} />
<KioskAlert {...kioskAlertInfo} />
</SWRConfig>
</KioskAlertContext.Provider>
</>
);
}
KioskAudio.ts
export const kioskAudio = () => {
const audio = new Audio();
const playAudio = (folder: string, file: string) => {
stopAudio();
audio.setAttribute('src', `/sounds/${folder}/${file}.mp3`);
audio.play();
};
const stopAudio = () => {
audio.pause();
audio.currentTime = 0;
};
return {
playAudio,
stopAudio,
};
};
KioskAlertError.tsx
const KioskAlertError: React.FC<IKioskAlertErrorProps> = ({playAudio, stopAudio}) => {
const [isShow, setIsShow] = useState(false);
const [content, setContent] = useState('');
useEffect(() => {
document.addEventListener('error', (data: CustomEvent) => {
const message = JSON.parse(data.detail);
const errorMessage = message.message;
setContent(getErrorMessage(message.message));
setIsShow(true);
switch (errorMessage) {
case 'Already Registered':
console.log('Already joined');
playAudio('alert', '2');
break;
case 'Can't find your numbers':
console.log('userNotFound');
playAudio('alert', '1');
break;
}
});
return () => {
document.removeEventListener('error', null);
};
}, []);
const getErrorMessage = (messageCode) => {
return messageCode;
};
return isShow ? (
<Alert
content={content}
okText={'OK'}
onOK={() => setIsShow(false)}
wrapperStyle={defaultWrapperStyle}
alertStyle={defaultAlertStyle}
upperSectionStyle={defaultUpperSectionStyle}
lowerSectionStyle={defaultLowerSectionStyle}
titleStyle={defaultTitleStyle}
contentStyle={defaultContentStyle}
cancelStyle={defaultButtonStyle}
okStyle={defaultButtonStyle}
/>
) : null;
};
export default KioskAlertError;
As you have used the audio variable inside your audio functions, the reference to the variable in function closures get lost between component re-renders. So you need to convert the kisokAudio util into a custom hook which holds the ref between renders & then use useKioskAudio instead of the simple function.
useKioskAudio.ts
import { useRef } from "react";
export const useKioskAudio = () => {
const audio = useRef(new Audio());
const playAudio = (folder: string, file: string) => {
stopAudio();
audio.current.setAttribute('src', `/sounds/${folder}/${file}.mp3`);
audio.current.play();
};
const stopAudio = () => {
audio.current.pause();
audio.current.currentTime = 0;
};
return {
playAudio,
stopAudio,
};
};
and then use it like
const { playAudio, stopAudio } = useKioskAudio();
in your app.tsx component.

How can I better conditionally render my components?

I have a lot of components being rendered based on different states that I'm using for a game. I'm currently using the method where I check the value of state with ampersands. I'm not sure if there's a different way I should do it, or if there's a more efficient cleaner way to do it.
I've looked up a few different ways but was wondering if someone could maybe give me suggestions for something that would work well with my code I have existing.
const App = () => {
const [startPlayer, setStartPlayer] = useState("");
const [endPlayer, setEndPlayer] = useState("");
const [gameSelected, setGameSelected] = useState(false);
const [gameStarted, setGameStarted] = useState(false);
const [gameWon, setGameWon] = useState(false);
const [winningTeam, setWinningTeam] = useState([]);
const [gameSolved, setGameSolved] = useState(false);
const isMobile = useMobileCheck();
const resetGame = () => {
setStartPlayer("");
setEndPlayer("");
setGameSelected(false);
setGameStarted(false);
setGameWon(false);
setGameSolved(false);
setWinningTeam([]);
};
const setGameType = (gameType) => {
setGameSelected(gameType);
};
const rollPlayers = (startYear, endYear) => {
axios.get(`/api/gettwoplayers?startYear=${startYear}&endYear=${endYear}`).then((res) => {
setStartPlayer(res.data[0]);
setEndPlayer(res.data[1]);
});
};
const startTheGame = () => {
setGameStarted(true);
};
const goBackToGameSelection = () => {
setGameSelected(false);
setGameStarted(false);
setStartPlayer("");
setEndPlayer("");
};
const userSetPlayer = (player, type) => {
if(type === "start") setStartPlayer(player);
if(type === "end") setEndPlayer(player);
};
const theGameWasWon = (history) => {
history.push(endPlayer);
setWinningTeam(history);
setGameWon(true);
};
const solveGame = () => {
setGameSolved(true);
axios.get(`/api/solve?startPlayer=${startPlayer}&endPlayer=${endPlayer}`).then((res) => {
console.log(res.data);
})
};
return (
<Container
sx={{
minHeight:'100vh',
maxWidth: "90vw!important",
}}
>
{
!gameSelected &&
!gameStarted &&
!gameWon &&
<ChooseGame setGameType={setGameType} />
}
{
!gameStarted &&
!gameWon &&
gameSelected === 'r' &&
<CreateRandomGame
rollPlayers={rollPlayers}
startPlayer={startPlayer}
endPlayer={endPlayer}
startTheGame={startTheGame}
goBack={goBackToGameSelection}
/>
}
{
!gameStarted &&
!gameWon &&
gameSelected === 's' &&
<CreateUserGame
startPlayer={startPlayer}
endPlayer={endPlayer}
userSetPlayer={userSetPlayer}
startTheGame={startTheGame}
goBack={goBackToGameSelection}
/>
}
{
!gameWon &&
gameStarted &&
<GameScreen
startPlayer={startPlayer}
endPlayer={endPlayer}
gameWon={theGameWasWon}
resetGame={resetGame}
solveGame={solveGame}
/>
}
{
gameWon &&
<GameWon
resetGame={resetGame}
winningTeam={winningTeam}
/>
}
</Container>
);
}
export default App;
Two things you could try:
Firstly, you've got a lot of boolean state - e.g. gameStarted, and a lot of it seems mutually-exclusive with other boolean state, for example gameStarted looks like it could never be true at the same time as gameWon. In situations like that, it can be a lot nicer to model the state as an enumerated type; unfortunately Javascript doesn't have them natively (look into TypeScript for a "true" enum type) but we can make do with strings:
const MODE_STARTED = 'started'
const MODE_SELECTED_RANDOM = 'random'
const MODE_SELECTED_USER = 'user'
const MODE_GAME_WON = 'won'
...
const [gameMode, setGameMode] = useState(MODE_STARTED);
...
Now rather than flipping individual booleans all over the place, you can just change your game mode ... e.g. setGameMode(MODE_SELECTED_RANDOM)
Once you've done that, your JSX can become cleaner too:
const showCorrectUI = () => {
switch (gameMode) {
case MODE_STARTED:
return <GameScreen {foo} />
case MODE_GAME_WON:
return <GameWon {bar} />
... // etc
}
}
return (
<Container
sx={{
minHeight:'100vh',
maxWidth: "90vw!important",
}}
>
{showCorrectUI()}
</Container>)

Warning: Using UNSAFE_componentWillMount in strict mode is not recommended (upgrade to CRA 4.0.2)

I updated my React application from 16.3+ to React 17 while upgrading to crate-react-app#4.0.2. Everything works as expected, but I see the following in the console:
Warning: Using UNSAFE_componentWillMount in strict mode is not recommended and may indicate bugs in your code. See react-unsafe-component-lifecycles for details.
* Move code with side effects to componentDidMount, and set initial state in the constructor.
Please update the following components: SideEffect(NullComponent)
My App.jsx file:
import React, { useRef, useEffect, useCallback, createRef } from 'react';
import { useDispatch, useSelector, batch } from 'react-redux';
import './App.scss';
import { CountryBox, Error, MasterBox, MetaTags, ModalContainer, ScreenLoader } from '../../components';
import { dataActions, settingsActions, statisticsActions, statisticsUpdatesActions } from '../../store/actions/actions';
import { engineService } from '../../services';
import { coreUtils } from '../../utils';
const App = (props) => {
const dispatch = useDispatch();
// Refs.
const elRefs = useRef([]);
// State variables.
const settingsList = useSelector((state) => state.settings.settingsList);
const loadingList = useSelector((state) => state.settings.loadingList);
const sourcesList = useSelector((state) => state.data.sourcesList);
const countriesList = useSelector((state) => state.data.countriesList);
const { isActive, isRefreshMode, viewType, isDisplayError, activeModalName,
activeModalValue, isReplaceModalMode, isActionLoader } = settingsList;
const { loadingPrecentage, isScreenLoaderComplete } = loadingList;
// Functions to update the state.
const onSetStateCurrentTime = (data) => dispatch(statisticsActions.setStateCurrentTime(data));
const onSetStateSettingsList = (listName, listValues) => dispatch(settingsActions.setStateSettingsList(listName, listValues));
const onSetStateStatisticsField = (fieldName, fieldValue) => dispatch(statisticsActions.setStateStatisticsField(fieldName, fieldValue));
const onSetStateStatisticsList = (statisticsList) => dispatch(statisticsActions.setStateStatisticsList(statisticsList));
const onSetStateStatisticsUpdatesSettingsList = (statisticsUpdatesSettingsList) => dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesSettingsList(statisticsUpdatesSettingsList));
const onSetStateDataCollection = (collectionName, collectionValue) => dispatch(dataActions.setStateDataCollection(collectionName, collectionValue));
const onSetStateInitiateSettings = (data) => {
const { settingsList, loadingList } = data;
batch(() => {
dispatch(settingsActions.setStateSettingsList('settingsList', settingsList));
dispatch(settingsActions.setStateSettingsList('loadingList', loadingList));
});
};
const onSetStateInitiateSources = (data) => {
const { sourcesList, countriesList, countriesNameIdList, statisticsList, settingsList } = data;
batch(() => {
dispatch(dataActions.setStateDataCollection('sourcesList', sourcesList));
dispatch(dataActions.setStateDataCollection('countriesList', countriesList));
dispatch(dataActions.setStateDataCollection('countriesNameIdList', countriesNameIdList));
dispatch(settingsActions.setStateSettingsList('settingsList', settingsList));
dispatch(statisticsActions.setStateStatisticsList(statisticsList));
});
};
const onSetStateUpdateRound = (data) => {
const { countriesList, statisticsList, updateStatisticsUpdatesListResults } = data;
const { statisticsUpdatesList, statisticsUpdatesSettingsList } = updateStatisticsUpdatesListResults;
batch(() => {
dispatch(dataActions.setStateDataCollection('countriesList', countriesList));
dispatch(statisticsActions.setStateStatisticsList(statisticsList));
if (statisticsUpdatesList && statisticsUpdatesList.length > 0) {
dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesList(statisticsUpdatesList));
dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesSettingsList(statisticsUpdatesSettingsList));
}
});
};
const onSetStateActionUpdate = (data) => {
const { countriesList, settingsList } = data;
batch(() => {
dispatch(dataActions.setStateDataCollection('countriesList', countriesList));
dispatch(settingsActions.setStateSettingsList('settingsList', settingsList));
});
};
const onSetStateActionRefresh = (data) => {
const { countriesList, settingsList, statisticsList, updateStatisticsUpdatesListResults } = data;
const { statisticsUpdatesList, statisticsUpdatesSettingsList } = updateStatisticsUpdatesListResults;
batch(() => {
dispatch(dataActions.setStateDataCollection('countriesList', countriesList));
dispatch(settingsActions.setStateSettingsList('settingsList', settingsList));
dispatch(statisticsActions.setStateStatisticsList(statisticsList));
if (statisticsUpdatesList && statisticsUpdatesList.length > 0) {
dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesList(statisticsUpdatesList));
dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesSettingsList(statisticsUpdatesSettingsList));
}
});
};
const onSetStateUpdateCountryVisibility = (data) => {
const { countriesList, countriesNameIdList, statisticsList, statisticsUpdatesList } = data;
batch(() => {
dispatch(dataActions.setStateDataCollection('countriesList', countriesList));
dispatch(dataActions.setStateDataCollection('countriesNameIdList', countriesNameIdList));
dispatch(statisticsActions.setStateStatisticsList(statisticsList));
if (statisticsUpdatesList && statisticsUpdatesList.length > 0) {
dispatch(statisticsUpdatesActions.setStateStatisticsUpdatesList(statisticsUpdatesList));
}
});
};
// Run the engine.
useEffect(() => {
engineService.runEngine({
mode: props.mode,
onSetStateCurrentTime: onSetStateCurrentTime,
onSetStateSettingsList: onSetStateSettingsList,
onSetStateStatisticsField: onSetStateStatisticsField,
onSetStateStatisticsList: onSetStateStatisticsList,
onSetStateStatisticsUpdatesSettingsList: onSetStateStatisticsUpdatesSettingsList,
onSetStateInitiateSettings: onSetStateInitiateSettings,
onSetStateInitiateSources: onSetStateInitiateSources,
onSetStateUpdateRound: onSetStateUpdateRound,
onSetStateDataCollection: onSetStateDataCollection,
onSetStateActionUpdate: onSetStateActionUpdate,
onSetStateActionRefresh: onSetStateActionRefresh,
onSetStateUpdateCountryVisibility: onSetStateUpdateCountryVisibility
});
return () => {
engineService.clearSources();
};
}, []);
// Set loader for each master action.
useEffect(() => {
engineService.updateActionLoader(false);
}, [countriesList]);
// After exit from any modal - Scroll back to the element's vertical position.
const scrollToCountry = useCallback((data) => {
const { action, value } = data;
if (action === 'modal' && !value && activeModalValue && !isReplaceModalMode && activeModalName !== 'country') {
setTimeout(() => {
const offsetTop = elRefs.current.find(c => c.current?.dataset?.countryId === activeModalValue).current.offsetTop;
if (offsetTop > window.innerHeight) {
window.scrollTo(0, offsetTop);
}
}, 10);
}
}, [elRefs, activeModalValue, isReplaceModalMode]);
// Update action on master modal click.
const handleActionClick = useCallback((e) => {
if (!isActionLoader) {
const data = {
action: coreUtils.getAttributeName(e, 'data-action'),
value: coreUtils.getAttributeName(e, 'name'),
id: coreUtils.getAttributeName(e, 'data-country-id')
};
scrollToCountry(data);
engineService.runMasterActionClick(data);
}
}, [elRefs, activeModalValue, isReplaceModalMode]);
// Update action on relevant modal change.
const handleModalActionChange = useCallback((e) => {
engineService.runModalActionUpdate({
modalName: coreUtils.getAttributeName(e, 'data-modal-name'),
action: coreUtils.getAttributeName(e, 'data-action'),
value: coreUtils.getValue(e)
});
}, []);
// Validate all OK to show the data and generate the countries.
const isInitiateComplete = !isDisplayError && countriesList && countriesList.length > 0 && loadingPrecentage === 100;
const renderCountries = useCallback(() => {
const countriesDOM = [];
const refsList = [];
for (let i = 0; i < countriesList.length; i++) {
const country = countriesList[i];
const ref = elRefs.current[i] || createRef();
refsList.push(ref);
countriesDOM.push(
(<CountryBox
key={country.id}
{...country} // React memo works only with separated properties.
isRefreshMode={isRefreshMode}
sourcesList={sourcesList}
onActionClick={handleActionClick}
ref={ref}
/>));
}
elRefs.current = refsList;
return countriesDOM;
}, [countriesList]);
return (
<div className="main">
{MetaTags}
{!isScreenLoaderComplete &&
<ScreenLoader
isActive={isActive}
loadingList={loadingList}
isDisplayError={isDisplayError}
/>
}
{isDisplayError &&
<Error
isDisplayError={isDisplayError}
/>
}
{activeModalName &&
<ModalContainer
onActionClick={handleActionClick}
onActionChange={handleModalActionChange}
/>
}
{isInitiateComplete &&
<div className="page">
<div className="main-container">
<div className={`container ${viewType} f32 f32-extra locations`}>
<MasterBox
onActionClick={handleActionClick}
/>
{renderCountries()}
</div>
</div>
</div>
}
</div>
);
};
export default App;
How can I fix this problem?
OK, I solved it.
The issue was with one of the components named MetaTags:
MetaTags.jsx
import React from 'react';
import { Helmet } from 'react-helmet';
import { timeUtils } from '../../../utils';
const MetaTags =
(<Helmet>
<title data-rh="true">World Covid 19 Data | Covid 19 World Data | {timeUtils.getTitleDate()}</title>
</Helmet>);
export default MetaTags;
The react-helmet package is outdated, and I needed to install 'react-helmet-async' instead, and change the code to:
initiate.jsx
app = (
<HelmetProvider>
<Suspense fallback={null}>
<Provider store={createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)))}>
<Helmet>
<title data-rh="true">Dynamic title {timeUtils.getTitleDate()}</title>
</Helmet>
<BrowserRouter>
{component}
</BrowserRouter>
</Provider>
</Suspense>
</HelmetProvider>
);
This solved my issue and the warning was gone.

Resources