Implement Window Data Layer Push in React App - javascript

I'm trying to implement window.data.layer.push in my react application so I can use it with Google Tag Manager but I am unsure where it would go. this is my base app.js file
// import the GTM Module so you can access it
import TagManager from "react-gtm-module";
const tagManagerArgs = {
gtmId: "GTM-P8J3MKF"
};
TagManager.initialize(tagManagerArgs)
const { persistor, store } = configureStore();
const MGMW = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
{/*<LoginScene className='main-background' />*/}
<LayoutBase />
<GlobalModals />
</PersistGate>
</Provider>
);
const rootElement = document.getElementById('app-root');
if (rootElement) render(<MGMW />, rootElement);
export default MGMW;

You must use useEffect hook.
useEffect(() => {
/*script to be executed here*/
}, [])
This is the componentDidMount version of React Hooks. More on the subject here: https://reactjs.org/docs/hooks-effect.html

Related

Why do we need to wrap the BrowserRouter in parent component instead of routes child component for react router v6

I tried to create useRoutes hook from react-router-dom#6.4.1 to create my App routes using JS, like this in my routes.jsx:
import { useRoutes, } from "react-router-dom";
import TestPage from "../Pages/Public/TestPage";
import TestPageTwo from "../Pages/Public/TestPageTwo";
const redirectRoutes = [
{
path: "/no-match",
element: () => <div>No Match found</div>,
},
];
const Router = () => {
const router = useRoutes([
{
path: "/testPage",
element: <TestPage />,
loader: false,
},
{
path: "/testPageTwo",
element: <TestPageTwo />,
loader: false,
},
...redirectRoutes,
]);
return <BrowserRouter>{router}</BrowserRouter>;
};
export default Router;
and in my app.jsx, I imported the file like so:
import { Provider } from "react-redux";
import Router from "./Router";
import initializeStore from "./Reducer/initializeStore";
import "./App.css";
export const store = initializeStore();
const App = () => {
return (
<Provider store={store}>
<Router />
</Provider>
);
};
export default App;
This resulted in the following error:
Uncaught Error: useRoutes() may be used only in the context of a component.
As you can see, I have wrapped the routes using BrowserRouter in the app.jsx, but I still get this error.
However, I was able to solve this when I moved the BrowserRouter to app.jsx instead of routes.jsx, like so:
app.jsx:
...
const App = () => {
return (
<Provider store={store}>
<BrowserRouter>
<Router />
</BrowserRouter>
</Provider>
);
};
...
and, in routes.jsx, I just return the router which is created using useRoutes();
I don't understand why do we need to wrap the BrowserRouter from react-router-dom#6 in the app.jsx like this instead of routes.jsx.
In react-router and react-router-dom the router components are the component that provides a routing context for all RRD hooks and components to access. It's a React context and needs to be provided higher in the ReactTree than any of the components that are consuming it.
Doesn't work:
const Router = () => {
const router = useRoutes([ // <-- accessed here outside context, error!!
....
]);
return <BrowserRouter>{router}</BrowserRouter>; // <-- provided here
};
...
const App = () => {
return (
<Provider store={store}>
<Router />
</Provider>
);
};
Works:
const Router = () => {
const router = useRoutes([ // <-- accessed here inside context, no issue :)
....
]);
return router;
};
...
const App = () => {
return (
<Provider store={store}>
<BrowserRouter> // <-- provided here
<Router />
</BrowserRouter>
</Provider>
);
};
See React Context API for more details.

blank screen after wrapping App component with react-context

I am writing the context API and everything is working fine but when I wrapped the App component with the context screen became blank
Code of contex
import { useState } from "react";
import { createContext, useContext } from "react";
const chatContext = createContext();
const ChatContext = ({ childern }) => {
const [user, setuser] = useState();
return (
<chatContext.Provider value={{ user, setuser }}>
{childern}
</chatContext.Provider>
);
};
export const ChatState = () => {
return useContext(chatContext);
};
export default ChatContext;
code of index.js before wrapping contex
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById("root")
);
**code after wrapping context api **
import ChatContext from "./Context/ChatContext";
ReactDOM.render(
<ChatContext>
<Router>
<App />
</Router>
</ChatContext>,
document.getElementById("root")
);
but the screen becomes blank anyone how can help me.
I tried to solve this problem but can not able to do so. plz anyone how can help me will be appricated
i think you just misspelled children you wrote childern and if you fix how you wrote it the problem will be solved
const ChatContext = ({ *childern* children }) => {
const [user, setuser] = useState();
return (
<chatContext.Provider value={{ user, setuser }}>
{*childern* children}
</chatContext.Provider>
);
};
export const ChatState = () => {
return useContext(chatContext);
};
export default ChatContext;

Invariant Violation: Element type is invalid: expected a string or a class but got: undefined. Check the render method of `MyApp`

I'm trying to load a static HTML from the meteor server side that also uses redux and router. However, every time I try to render my component with renderToString() I get the error indicated in the title. What am I doing wrong?
I've already tried using React.renderComponentToString as a possible alternative, but I get the error that React.renderComponentToString is not a function. How else am I going to pass an argument?
import React from 'react';
import {onPageLoad} from 'meteor/server-render';
import {StaticRouter} from 'react-router';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import {Helmet} from 'react-helmet';
import rootReducer, {initialState} from '../redux/reducers';
import HomePage from '../ui/homepage/HomePage';
export default renderServerPage = onPageLoad(sink => {
const context = {};
const store = createStore(rootReducer, initialState, applyMiddleware(thunk));
const MyApp = props => {
return (
<Provider store={store}>
<StaticRouter location={sink.request.url} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
// The following line is causing the error
sink.renderIntoElementById('app', renderToString(<MyApp />));
const helmet = Helmet.renderStatic();
sink.appendToHead(helmet.title.toString(
"Afterschools, Enrichment Programs, Growth, & Experiences - Fun2Bright"
));
sink.appendToBody(
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script>
);
});
My other attempts include the following:
1) creating a component outside of the scope within the same file and passing store and sink.request.url as props
function MyApp (props) {
const context = {};
return (
<Provider store={props.store}>
<StaticRouter location={props.location} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
2) basically creating the same component but in another file and importing the component.
3) directly putting the element inside the renderToString:
sink.renderIntoElementById('app', renderToString(
<Provider store={store}>
<StaticRouter location={sink.request.url} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
));
4) using React.createElement without passing any props:
sink.renderIntoElementById('app', renderToString(React.createElement(MyApp)));
5) commenting out the following just to see if it's caused by any of my other imported components
<Route path="/" component={HomePage}/>
I finally figured the issue. It turns out that simply using react-router doesn't allow me to use DOM-aware components like and , so I needed to use react-router-dom instead. react-router-dom also re-exports all of react-router's exports, so I'll only ever need to use react-router-dom. I changed everything to be imported from 'react-router-dom':
import {Route, StaticRouter} from 'react-router-dom';
...
// inside onPageLoad
const App = props => {
return (
<Provider store={store}>
<StaticRouter location={props.location} context={context}>
<Route path="/" component={HomePage}/>
</StaticRouter>
</Provider>
);
}
sink.renderIntoElementById('app', renderToString(<App store={store} location={sink.request.url}/>));
I found this from here: https://github.com/ReactTraining/react-router/issues/4648

Basename not working connected-react-router

I'm using connected-react-router with my react redux app.
I need server side rendering and client side rendering (I'm using a react component in a symfony twig template via limenius react bundle).
My probleme is that i cannot use basename properly. I have a locale isocode in my URL (www.localhost.com/fr/mypage)
If i declare a basename '/fr/' in history:
<Route exact path={`/${isocode}/checkout/customize`} component={Customize} />
works !
... but I want this :
<Route exact path="checkout/customize" component={Customize} />
and it does not work !
What i have in my app.js:
export const App = () => {
const store = ReactOnRails.getStore('CustomizeStore');
const state = store.getState();
const { isocode } = state.general.data.locale;
const history = createHistory({
basename: `/${isocode}/`,
initialEntries: [state.router.location.pathname],
});
return (
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route exact path={`/${isocode}/checkout/customize`} component={Customize} />
</Switch>
</ConnectedRouter>
</Provider>
);
};
and in my store.js
export const createHistory = historyConfig =>
isServer ? createMemoryHistory(historyConfig) : createBrowserHistory();
export default (props, context) => {
const { baseURL } = props.general.data.api;
const { isocode } = props.general.data.locale;
const history = createHistory({ basename: `/${isocode}/`, initialEntries: [context.pathname] });
return createStore(
reducers(history),
{ ...props },
composeEnhancers(
applyMiddleware(thunk, routerMiddleware(history)),
),
);
};
What i expect in my app.js:
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route exact path="checkout/customize" component={Customize} />
</Switch>
</ConnectedRouter>
</Provider>
I've read that the basename for "browserRouter" and "staticRouter" provided by react-router should be declared in history props of ConnectRouter component.
What I'm doing wrong ? Is connect-react-router a good choice for my redux ssr application or should i use react-router ? (I'm using immutable.js and i want to implement hot-reloading if possible =)
A big thanks !
I faced the same problem a few days ago and I solved it by setting the basename in the createBrowserHistory, like this:
const history = createBrowserHistory({ basename: “/baseName” })

The prop `push` is marked as required

I'm getting this warning when i call the ReactDOM.render() method:
Failed prop type: The prop push is marked as required in
Connect(Detail), but its value is undefined
This is the render call:
const render = Component => {
const appElement = document.getElementById('app');
ReactDOM.render(
<AppContainer>
{Component}
</AppContainer>,
appElement
);
};
And this is my component:
const component = (
<Provider store={store}>
<ConnectedRouter history={createBrowserHistory()}>
{routes()}
</ConnectedRouter>
</Provider>
);
Then, I call it like this:
render(component);
Do I need extra configuration on the ConnectedRouter or maybe I'm not building properly the routes and/or store?

Categories

Resources