I want to set a cookie to be on true all the time, not when something is happening or something is clicked.
So there are several tutorials and articles about that. In my case it should be something like: 'mySpecialCookie = true'.
Installing the package: npm install react-cookie
Does it need to be imported in both index.js and App.js?
My index.js looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import configureStore from './store/configureStore';
import getMiddlewares from './middlewares';
import App from './containers/App';
import * as serviceWorker from './serviceWorker';
const storeConfig = configureStore(getMiddlewares());
ReactDOM.render(
<storeConfig.Provider store={storeConfig.store}>
<App />
</storeConfig.Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
So I assume that inside ReactDOM it should be changed to this?
import { CookiesProvider } from "react-cookie";
...
ReactDOM.render(
<storeConfig.Provider store={storeConfig.store}>
<CookiesProvider>
<App />
</CookiesProvider>
</storeConfig.Provider>,
document.getElementById('root')
);
And in App.js I added it using useCookies hooks but don't know where to use it:
import React, { useEffect } from 'react';
import { useCookies } from 'react-cookie'; //// <--- added it here
import { IntlProvider } from 'react-intl';
import { useSelector, shallowEqual, useDispatch } from 'react-redux';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Main from './Main';
import OrderDetails from './OrderDetails';
import { fetchDictionary } from '../actions/dictionary';
import { getLanguageCode } from '../utils';
import { HOME_PAGE, ORDER_DETAILS } from '../constants/routes';
const App = () => {
const dictionary = useSelector((state) => state.dictionary, shallowEqual);
const routes = [
{ path: HOME_PAGE, component: Main },
{ path: `${ORDER_DETAILS}/:id`, component: OrderDetails }
];
const dispatch = useDispatch();
const [mySpecialCookie, setMySpecialCookie] = useCookies(true); //// <--- added it here
useEffect(() => {
dispatch(fetchDictionary(getLanguageCode()));
}, [dispatch]);
return (
<IntlProvider
key={dictionary.locale}
locale={dictionary.locale}
messages={dictionary.messages}>
<Router>
{routes.map((route, index) => (
<Route
key={index}
path={route.path}
exact
component={route.component}
/>
))}
</Router>
</IntlProvider>
);
};
export default App;
Any suggestions?
I have found a much shorter way to do it using js-cookie.
In the App.js file:
...
import Cookies from 'js-cookie';
...
const App = () => {
...
Cookies.set('mySpecialCookie', true);
...
}
Related
After updating to react router V6 my component no longer renders:
Trying to render the home component within my app, seems like the router is correctly organized according to React Router V6.
I am able to render the "SubredditAside" component which is located outside of the in the App.js but trying to render the Home component doesnt seem to be working
App.js:
import React from 'react';
import {
BrowserRouter,
Routes,
Route,
Router,
} from "react-router-dom";
import { selectDarkMode } from "../features/Theme/themeSlice";
import { useSelector } from "react-redux";
import './App.css';
import "../features/Theme/theme.css";
import Header from "../features/Header/Header";
import Home from "../features/Home/Home";
import SearchResults from "../features/SearchResults/SearchResults";
import SubredditsAside from "../features/SubredditsAside/SubredditAside";
import Subreddit from "../features/Subreddit/Subreddit";
import NotFoundPage from '../features/NotFoundPage/NotFoundPage';
function App() {
const darkMode = useSelector(selectDarkMode);
return (
<BrowserRouter>
<div id="app-container" className={darkMode ? "dark" : "light"}>
<Header />
<main>
<Routes>
<Route path="/" component={Home}/>
<Route path="/r/:id" component={Subreddit}/>
<Route path="/search/:id" component={SearchResults}/>
<Route component={NotFoundPage} />
</Routes>
</main>
<aside>
<SubredditsAside />
</aside>
</div>
</BrowserRouter>
);
}
export default App;
Home.js
import React, { useEffect } from "react";
import Filters from "../Filters/Filters";
import Post from "../Post/Post";
import PostLoading from "../Post/PostLoading";
import NotFoundPage from "../NotFoundPage/NotFoundPage";
import { AnimatedList } from "react-animated-list";
import { useDispatch, useSelector } from "react-redux";
import {
loadPostsHot,
selectPosts,
selectIsLoading,
selectError,
} from "../../app/appSlice";
import { setCurrentSubreddit } from "../SubredditsAside/SubredditAsideSlice"
import { setCurrentFilter } from "../Filters/filtersSlice";
const Home = ({ match }) => {
const dispatch = useDispatch();
const posts = useSelector(selectPosts);
const isLoading = useSelector(selectIsLoading);
const error = useSelector(selectError);
const currentSubreddit = match.params.id;
useEffect(() => {
dispatch(setCurrentFilter("hot"));
dispatch(setCurrentSubreddit(""));
dispatch(loadPostsHot());
}, [dispatch, currentSubreddit]);
if (error) {
return <NotFoundPage />;
}
return (
<>
<Filters />
{isLoading ? (
<AnimatedList>
<PostLoading />
<PostLoading />
<PostLoading />
</AnimatedList>
) : (
posts.map((post, index) => (
<Post key={index} post={post} postIndex={index} />
))
)}
</>
);
};
export default Home;
Index.js:
import React from 'react';
import { ReactDOM } from 'react';
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './app/store';
import App from '../src/app/App';
import reportWebVitals from './reportWebVitals';
import './index.css';
import "#fontsource/roboto";
// import "./base.css";
import { BrowserRouter } from 'react-router-dom';
const container = document.getElementById('root');
const root = createRoot(container);
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
It's the HomePage component of ReactJS
import React from 'react';
import axios from 'axios';
import { useState, useEffect } from 'react';
import { useNavigate,useParams } from 'react-router-dom';
import { Main } from '../components/Main';
import { Controls } from '../components/Controls';
import { ALL_COUNTRIES } from '../config';
import { List } from '../components/List';
import { Card } from '../components/Card';
import { Details } from './Details';
export const HomePage = () => {
const [countries,setCountries] = useState([]);
const navigate = useNavigate();
useEffect(() => {
axios.get(ALL_COUNTRIES).then(({data})=>setCountries(data))
},[]);
return (
<>
<Controls/>
<List>
{
countries.map((c) => {
const countryInfo = {
img: c.flags.png,
name: c.name,
info: [
{
title:'Population',
description:c.population.toLocaleString(),
},
{
title:'Region',
description:c.region,
},
{
title:'Flag',
description:c.capital,
},
],
};
return (
<Card
key={c.name}
onClick={(e) => {
navigate('/country/${c.name}');
}}
{...countryInfo}
/>
)
})
}
</List>
</>
);
};
It's second components Details
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({match,params}) => {
const { name } = useParams();
return (
<div>
Details {match.params.name}
</div>
);
};
config.js
const BASE_URL = 'https://restcountries.com/v2/';
export const ALL_COUNTRIES=BASE_URL+"all?fields=name,flags,population,capital,region";
export const searchByContry=(name)=>BASE_URL+'name/'+name;
export const filterByCode=(code)=>BASE_URL+'alpha?code'+code.join('');
APP.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import { Route,Routes,Router,useParams} from 'react-router-dom';
import {useState, useEffect} from 'react';
import './App.css';
import styled from 'styled-components';
import Header from './components/Header';
import { Main } from './components/Main';
import {NotFound} from './pages/NotFound';
import { HomePage } from './pages/HomePage';
import { Details } from './pages/Details';
function App() {
return (
<>
<Header/>
<Main>
<Routes>
<Route path="/" element={<HomePage/>}/>
<Route path="country/:name" element={<Details/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</Main>
</>
);
}
export default App;
HomePage itself looks like this
but when I click on flag/card it sends me on second page as expected but gives me this error
[2]:https://i.stack.imgur.com/39HEw.png
Also, I'm using react-router-domV6 and Axios
and this API https://restcountries.com/v2/all
also both Components are in
APP.js
Details is trying to read params from an undefined object, props.match in this case.
<Route path="country/:name" element={<Details />} /> // <-- no props passed!
...
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({ match, params }) => { // <-- match undefined
const { name } = useParams();
return (
<div>
Details {match.params.name} // <-- Oops, can't read params of undefined
</div>
);
};
Remove the props and access the values returned from the useParams hook.
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = () => {
const { name } = useParams();
return (
<div>
Details {name}
</div>
);
};
The target path is also malformed. The code navigate('/country/${c.name}') is navigating to the string literal "/country/${c.name}", which is likely not what you meant to do. Fix this to use a string template literal instead to inject the c.name value into the target path.
navigate(`/country/${c.name}`) // note the backticks instead of single quotes
I oftentimes find it useful/helpful to use the generatePath utility function to create path values.
Example:
import { generatePath, useNavigate } from 'react-router-dom';
...
const path = generatePath("/country/:name", { name: c.name });
navigate(path);
I am using auth0 for authentication in react app. My app is just button that would lead to auth0 page. However when I use <Auth0ProviderWithHistory> it doesn't render.
index.js File
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Auth0ProviderWithHistory from './auth0provider';
ReactDOM.render(
<React.StrictMode>
<Auth0ProviderWithHistory>
<App />
</Auth0ProviderWithHistory>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
App.js File:
import"./App.css"
import React from "react"
import Auth0ProviderWithHistory from "./auth0provider"
import { useAuth0 } from "#auth0/auth0-react"
import Button from '#mui/material/Button';
function App() {
const {
isLoading,
isAuthenticated,
error,
user,
loginWithRedirect,
logout,
} = useAuth0();
return(
<Button variant="contained" onClick={() => loginWithRedirect }>Contained</Button>
)
}
export default App;
The code was taken from https://auth0.com/blog/complete-guide-to-react-user-authentication/
[Webpage with error][1]
auth0provider.js file:
import React from 'react';
import { useNavigate} from 'react-router-dom';
import { Auth0Provider } from '#auth0/auth0-react';
const Auth0ProviderWithHistory = ({ children }) => {
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
const history = useNavigate();
const onRedirectCallback = (appState) => {
history.push(appState?.returnTo || window.location.pathname);
};
return (
<Auth0Provider
domain={domain}
clientId={clientId}
redirectUri={window.location.origin}
onRedirectCallback={onRedirectCallback}
>
{children}
</Auth0Provider>
);
};
export default Auth0ProviderWithHistory;
Console Error
I am trying server side rendering using react-router 4. I am following the example provided here https://reacttraining.com/react-router/web/guides/server-rendering/putting-it-all-together
As per the example on server we should use StaticRouter. When I import as per the example I am seeing StaticRouter as undefined
import {StaticRouter} from 'react-router';
After doing some research online I found I could use react-router-dom. Now my import statement looks like this.
import {StaticRouter} from 'react-router-dom';
However when I run the code I am getting Invariant Violation: Browser history needs a DOM in the browser.
my server.js file code
....
app.get( '*', ( req, res ) => {
const html = fs.readFileSync(path.resolve(__dirname, '../index.html')).toString();
const context = {};
const markup = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context} >
<App/>
</StaticRouter>
);
if (context.url) {
res.writeHead(302, {
Location: context.url
})
res.end();
} else {
res.send(html.replace('$react', markup));
}
} );
....
And my client/index.js code
....
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), root);
....
Update v1
Reduced my example to a bear minimum and still getting the same error.
clientIndex.js
import ReactDOM from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from '../App'
ReactDOM.render((
<BrowserRouter>
<App/>
</BrowserRouter>
), document.getElementById('app'))
serverIndex.js
import { createServer } from 'http'
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { StaticRouter } from 'react-router'
import App from '../App'
createServer((req, res) => {
const context = {}
const html = ReactDOMServer.renderToString(
<StaticRouter
location={req.url}
context={context}
>
<App/>
</StaticRouter>
)
res.write(`
<!doctype html>
<div id="app">${html}</div>
`)
res.end()
}).listen(3000);
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import routes from "./client/routes";
const App = ( ) => (
<Router>
<Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
</Router>
)
export default App;
You need to use different history provider for server side rendering because you don't have a real DOM (and browser's history) on server. So replacing BrowserRouter with Router and an alternate history provider in your app.js can resolve the issue. Also you don't have to use two wrappers. You are using BrowserRouter twice, in app.js as well as clientIndex.js which is unnecessary.
import { Route, Router } from 'react-router-dom';
import { createMemoryHistory } from 'history';
const history = createMemoryHistory();
<Router history={history}>
<Route path="/" exact render={( props ) => ( <div>Helloworld</div> )} />
</Router>
You can now replace StaticRouter with ConnectedRouter which can be used both in client and server. I use the following code to choose between history and export it to be used in ConnectedRouter's history.
export default (url = '/') => {
// Create a history depending on the environment
const history = isServer
? createMemoryHistory({
initialEntries: [url]
})
: createBrowserHistory();
}
In clientIndex.js
Rather than BrowserRouter use StaticRouter.
import { BrowserRouter } from 'react-router-dom';
import { StaticRouter } from 'react-router-dom'
As is essentially noted in the comments, one may hit this error (as I have) by accidentally wrapping your App component in a <BrowserRouter>, when instead it is your client app that should be wrapped.
App.js
import React from 'react'
const App = () => <h1>Hello, World.</h1>
export default App
ClientApp.js
import React from 'react'
import { BrowserRouter } from 'react-router-dom'
import ReactDOM from 'react-dom'
import App from './App'
const render = Component => {
ReactDOM.render(
<BrowserRouter>
<Component />
</BrowserRouter>,
document.getElementById('app')
)
}
render(App)
See also the React Router docs.
I have wrapped my index.js file to support a Redux Store and React-Router-v4.
However, when I try to run a basic test, I get the following error message:
Invariant Violation: You should not use <Route> or withRouter() outside a <Router>
Here is what my index.js looks like:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
import registerServiceWorker from './registerServiceWorker';
// Redux
import { Provider } from 'react-redux';
import store from "./store/index";
ReactDOM.render((
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
), document.getElementById('root'));
registerServiceWorker();
and here is my App.js:
import React, { Component } from 'react';
import { ScaleLoader } from 'react-spinners';
import { withRouter } from 'react-router';
import Header from './components/Header';
import Footer from './components/Footer';
import Main from './Main';
import './styles/styles.scss';
// Redux
import { connect } from 'react-redux';
import store from "./store/index";
import { isLoading } from "./actions/index";
class App extends Component {
constructor() {
super();
store.dispatch(isLoading(true));
}
componentDidUpdate(prevProps) {
if (this.props.location.pathname !== prevProps.location.pathname) {
store.dispatch(isLoading(true));
}
}
render() {
return (
<div className='App'>
<Header />
<div className='App__wrapper'>
<div className={'loading-spinner ' + (this.props.isLoading ? null : '--hide-loader')}>
<ScaleLoader
color={'#123abc'}
loading={this.props.isLoading}
/>
</div>
<Main />
</div>
<Footer />
</div>
);
}
}
const mapStateToProps = (state) => ({ isLoading: state.isLoading });
export default withRouter(connect(mapStateToProps)(App));
Since I'm using withRouter to wrap for navigation, is this method discouraged? Should I be setting up withRouter at the index.js level?
Thank you!
Try importing your BrowserRouter like this:
import { BrowserRouter as Router } from 'react-router-dom'
Then replace everywhere it appears BrowserRouter with Router instead.