react-router doesn't render components on server side - javascript

I using react-router and server side rending . but my server side not work with router . it change URL but doesn't render components
My server side code:
import express from 'express';
import cors from "cors";
import { renderToString } from "react-dom/server";
import App from '../shared/App';
import React from 'react';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from "../shared/reducers/index";
import { StaticRouter, matchPath } from "react-router-dom"
import { create } from 'domain';
const app = express();
app.use(express.static("public"));
app.use(cors());
app.use("*", (req, res, next) => {
let context = {};
const store = createStore(rootReducer)
const markup = renderToString(
<Provider store = {store}>
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
</Provider>
)
const preloadedState = store.getState();
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>SSR with RR</title>
</head>
<body>
<div id="app">${markup}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
</script>
<script src = "/bundle.js"></script>
</body>
</html>
`)
});
app.listen(3000, () => {
console.log('Server is running ....')
});
And this is my App code :
import React from 'react';
import { Route } from 'react-router-dom';
import List from "./List";
import { Link } from 'react-router-dom';
import Home from './Home';
import { connect } from "react-redux";
class App extends React.Component {
render() {
return (
<div>
Hello
<ul>
<li><Link to="/list">List</Link></li>
<li><Link to="/home"> Home</Link></li>
</ul>
<Route component={List} path="/list" />
<Route component={Home} path="/home" exact />
</div>
);
}
};
export default connect(null,null)(App);
my List and Home components render string "Home" and "List"
my index.js code
import React from "react";
import ReactDOM from "react-dom";
import App from "../shared/App";
import { createStore, applyMiddleware } from "redux";
import { Provider } from "react-redux";
import rootReducer from "../shared/reducers/index";
import { BrowserRouter } from 'react-router-dom';
const preloadedState = window.__PRELOADED_STATE__;
delete window.__PRELOADED_STATE__
const store = createStore(rootReducer, preloadedState);
ReactDOM.hydrate(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById("app"));
This is my all code it CHange URL but dont load component

Solved the problem , i have to add withRouter from react-router-dom to app component
withRouter(connect(null,null)(App));

Related

React-Router-Dom (v6) not working / Can't render the home component

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>
);

Set a cookie in react to true all the time

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);
...
}

HashRouter show File:// on build

Why my project show Index of folder when build, but when it running, it works
My Index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from "./reducers";
import { HashRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
import createBrowserHistory from "history/createBrowserHistory";
const store = createStore(rootReducer);
const history = createBrowserHistory();
ReactDOM.render(
<Provider store={store}>
<HashRouter history={history}>
<App />
</HashRouter>
</Provider>,
document.getElementById("root")
);
My App.js
import React, { Component } from "react";
export default class App extends Component {
render() {
return (
<div>
<h1>ABC</h1>
</div>
);
}
}
When i call my index.html and my bundle.js after build

React Server Side Rendering not outputting index page

I've been playing with Server Side Rendering (SSR) with React and I've pretty much got it working, with the exception of the homepage not loading from the server.
If I use alternative routes e.g /test or /404 it loads from the server. If I go to the / index path, it just loads my react app, but not html from the server. I tested this by disabling javascript and noticed it happening.
Here is my server code I'm using:
import path from 'path';
import fs from 'fs';
import React from 'react';
import express from 'express';
import cors from 'cors';
import configureStore from '../src/redux/store/configureStore';
import { Provider } from 'react-redux';
import { StaticRouter } from 'react-router-dom';
import { renderToString } from 'react-dom/server';
import Client from '../src/client/index.jsx';
/* Express settings */
const app = express();
const PORT = process.env.PORT || 3334;
app.disable('x-powered-by');
app.use(cors());
app.use(express.static('./dist'));
app.use(handleRender);
/* Handle React Application */
function handleRender(req, res) {
const context = {};
const store = configureStore({});
const indexFile = path.resolve('./dist/index.html');
const html = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={context}>
<Client />
</StaticRouter>
</Provider>
);
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
}
res.status(context.status||200).send(
data.replace(
'<div id="root"></div>',
`
<div id="root">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(store)}
</script>
`
)
);
});
}
/* Listen for connections */
app.listen(PORT, () => {
console.log(`💻 😎 Server is running on port ${PORT}`);
});
Here is my primary react component with the routes:
import React from 'react';
import {
Switch,
Route
} from 'react-router-dom';
import App from './components/App/index.jsx';
import NotFound from './NotFound.jsx';
const Test = () => (
<h1>Test!</h1>
);
const Bruh = () => (
<h1>Bruh!</h1>
);
const Client = () => (
<Switch>
<Route path="/" exact component={App} />
<Route path="/test" exact component={Test} />
<Route path="/bruh" exact component={Bruh} />
<Route component={NotFound} />
</Switch>
);
export default Client;
Finally, here is my index.js file for my react app:
import React from 'react';
import { hydrate } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import configureStore from './redux/store/configureStore';
import Client from './client/index.jsx';
import './styles/index.css';
/* Redux */
const preloadedState = window.__PRELOADED_STATE__ = {}; //initial state
delete window.__PRELOADED_STATE__;
const store = configureStore(preloadedState);
const unsubscribe = store.subscribe( () => {
console.log("Store: ", store.getState());
});
/* Render / Hydrate App */
hydrate(
<Provider store={ store }>
<BrowserRouter>
<Client />
</BrowserRouter>
</Provider>,
document.getElementById('root')
);
I think that's everything. Let me know if you need more info. Any advice and help would be greatly appreciated.
Thanks!

You should not use <Route> or withRouter() outside a <Router>

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.

Categories

Resources