react-router 4 not re-render when clicking <Link> - reactjs

I'm working on server-side rendering, so far the initial page can be rendered with react-router successfully according to the path entered to the browser e.g. /, /customers
Code
Routes.jsx
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import Home from './Home'
import CustomerList from './CustomerList'
const PageNotFound = () => <div className="box">
<h3 className="title">Page Not Found</h3>
</div>
export default () => {
return <div>
<Switch>
<Route exact path="/" component={ Home } />
<Route path="/customers" component={ CustomerList } />
<Route component={ PageNotFound }></Route>
</Switch>
</div>
}
NavBar.jsx
import React from 'react'
import { Link } from 'react-router-dom'
export default () => <nav className="nav">
<div className="nav-right">
<Link to="/" className="nav-item is-tab">Home</Link>
<Link to="/customers" className="nav-item is-tab">Customer</Link>
</div>
</nav>
Problem
I'm only successful with server-side rendering, but I cannot get re-render with the client version, when clicking on any of the links there is no re-rendering happens (only the URL gets changed on the browser)
So I have tried with below coding
Routes.jsx
const renderCustomerList = () => {
console.log('OK')
return <CustomerList />
}
...
<Route path="/customers" render={ renderCustomerList } />
I still cannot see the log on the client version
I believe I have done with the same coding as the client-side only version (no problems on the client-side only version), so please guide how to solve the problem
Thanks all

I encounter problems with the same symptom, but may not be the same cause since your index.js is not provided here. I hope you have already solved your problem so I just put my findings here for others references.
Go check your root render function in your index.js for both client-side and server-side rendering, mine is as follows with redux:
// React 16 global polyfill for IE < 11
import 'core-js/es6/map'
import 'core-js/es6/set'
import * as React from 'react'
import ReactDom from 'react-dom'
import { Provider, connect } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom'
import store from '~/store'
import App from './App'
const mapStateToProps = (state) => ({...state})
const mapDispatchToProps = {}
const render = App => {
const Connect = connect(mapStateToProps, mapDispatchToProps)(App)
ReactDom.hydrate(
<Provider store={store}>
<Router>
<Connect />
</Router>
</Provider>,
document.getElementById('root')
)
}
render(App)
My solution is simply to use <App /> instead of <Connect />, connect store inside children Components.
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>

Related

The <Provider> component does not pass the store and the page is not rendered

The component does not pass the store into 'connect()()' and the page is not rendered.
code in the file index.js:
import React from 'react';
import ReactDOM from 'react-dom/client';
import store from './redux/storeRedux.js';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { Provider } from 'react-redux';
const root = ReactDOM.createRoot(document.getElementById('root'));
let rerenderEntireTree = () => {
root.render(
<React.StrictMode>
<Provider store={store} >
<App />
</Provider>
</React.StrictMode>
);
}
rerenderEntireTree(store.getState());
store.subscribe(rerenderEntireTree);
code in component :
import React from 'react';
import './App.css';
import Dialogs from './components/Dialogs/Dialogs';
import Footer from './components/Footer/Footer.jsx';
import Header from './components/Header/Header.jsx';
import Profile from './components/Profile/Profile.jsx';
import SideBar from './components/SideBar/SideBar.jsx';
import News from './components/News/News.jsx';
import Music from './components/Music/Music.jsx';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Settings from './components/Settings/Settings.jsx';
const App = (props) => {
return (
<BrowserRouter>
<div className="app-wrapper">
<Header />
<SideBar />
<div className="app-wrapper-content">
<Routes>
<Route path='/profile' element={<Profile />} />
<Route path='/dialogs/*' element={<Dialogs />} />
<Route path='/news' element={<News />} />
<Route path='/music' element={<Music />} />
<Route path='/settings' element={<Settings />} />
</Routes>
</div>
<Footer />
</div>
</BrowserRouter>
);
}
export default App;
code in component :
import React from 'react';
import MyPostsContainer from './MyPosts/MyPostsContainer';
import classes from './Profile.module.css'
import ProfileInfo from './ProfileInfo/ProfileInfo';
const Profile = (props) => {
return (
<main className={classes.mainBlock}>
<ProfileInfo />
<MyPostsContainer />
</main>
)
}
export default Profile;
Code in component :
import React from 'react'; //My vsCode output massage -- Never use. Some body know why ?
import { connect } from 'react-redux';
import { addPostActionCreator, updateNewPostTextActionCreator } from '../../../redux/ProfileReducer';
import MyPosts from './MyPosts';
let mapStateToProps = (state) => {
return {
posts: state.profilePage.postsData,
newPostText: state.profilePage.newPostText,
}
};
let mapDispatchToProps = (dispatch) => {
return {
updateNewPostText: (text) => {
dispatch(updateNewPostTextActionCreator(text))
},
addPost: () => {
dispatch(addPostActionCreator())
},
}
};
const MyPostsContainer = connect(mapStateToProps, mapDispatchToProps)(MyPosts);
export default MyPostsContainer;
In docementation React-Redux i read that problem could be in ESlint but it is not ((
Maybe it is foolish quation but i learning React and React-Redax and wanna understant how to use it.
Thanks for all who will hepl.
#React #Redux #React-Redux #Provider #Component #connect
I wanna use from React-Redux and send my store into my conteiner component MyPostsContainer used 'connect()()'.
Output: My SPA is not rendering
I'm confused on a couple parts.
First, it's not clear what actual error you're seeing. When you say "the SPA is not rendering", do you mean that nothing shows up on screen at all?
Next, a couple pieces of the setup code look wrong:
rerenderEntireTree(store.getState());
store.subscribe(rerenderEntireTree);
As written, your rerenderEntireTree function does not need store.getState() passed in, so you can remove that. You also don't need to call store.subscribe() at all. React-Redux will do that for you.
That said, this looks like it ought to run overall.
Also, while it's not a direct answer to your question, you should know that this is a very outdated approach to writing Redux code. With "modern Redux", we use the React-Redux hooks API (useSelector/useDispatch), and do not use connect() or "container components". I'd recommend going through our Redux docs tutorials: https://redux.js.org/tutorials/essentials/part-2-app-structure .
update
Unfortunately your app setup is now very wrong :( Looking at the repo link you provided, you have:
const root = ReactDOM.createRoot(document.getElementById('root'));
let rerenderEntireTree = (state) => {
root.render(
<React.StrictMode>
<App state={store.getState()}
dispatch={store.dispatch.bind(store)}
// publicMassage={store.publicMassage.bind(store)}
// updateNewMassageText={store.updateNewMassageText.bind(store) }
/>
</React.StrictMode>
);
}
rerenderEntireTree(store.getState());
store.subscribe(rerenderEntireTree);
That is not how you're supposed to use React-Redux, at all:
You should not pass store.getState() to the rest of the app code
You should not pass store.dispatch down yourself
You should not call store.subscribe() manually
React-Redux will do all that for you.
You also do not need a rerenderEntireApp function, either.
Your first example was closer. You need to wrap your <App> component in <Provider store={store}..
A correct setup would be:
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode
)
and then you should use the useSelector and useDispatch hooks in your components.
Unfortunately you seem to be following some very outdated and incorrect tutorials.
Please go through our official Redux docs tutorials - they'll show you the correct way to use Redux and React-Redux:
https://redux.js.org/tutorials/index

react-router-dom : updates url but does not render the new component

I am a bit lost with this issue for a whole day.
On button click the url changes but does not render the new page and I don't understand why.
I am using react-dom-router 5.2.0
INDEX JS
import {Router} from 'react-router-dom';
import history from './history';
ReactDOM.render(
<React.StrictMode>
<Router history={history}>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
APP JS
import Server from './Server';
import React from 'react';
function App() {
return (
<Server />
);
}
export default App;
SERVER JS
export default class Server extends Component
{
render()
{
return(
<div className="Homepage" >
<h1 className="header">Server</h1>
<button className="button"
onClick={() => history.push('/control')}>
Lets go
</button>
}
</div>
);
}
}
Please Note : I added <Control/> directly in the render method above and it renders the component all well .
CONTROL JS
import React, {Component} from 'react';
import Page2_View from './Page2_View';
export default class Control extends Component
{
constructor(props)
{
super(props);
}
render()
{
return(
<Page2_View/>
);
}
}
Page2_View
import React, {Component} from 'react';
const Page2_View = (props) =>
{
return(
<h1> PAGE 2 VIEW </h1>
);
}
export default Page2_View;
ROUTES JS
import {BrowserRouter as Router, Route, Redirect, Switch} from 'react-router-dom';
const Routes = () =>
{
return(
<Router>
<div>
<Switch>
<Route exact path="/test" component={Server}/>
<Redirect from = '/test' to = '/control'/>
<Route exact path="/control" component={Control}/>
</Switch>
</div>
</Router>
);
}
export default Routes;
HISTORY JS
import {createBrowserHistory as history} from 'history';
export default history();
I appreciate all the help. Thank you
I think the problem is that react-router-dom is not aware of this history.push('/control') you're doing; i.e. if you want to redirect to another route, it should be through react-router, not outside of it.
You have a few options:
Use the useHistory hook: https://reacttraining.com/react-router/web/api/Hooks/usehistory
Your button could be wrapped in a Link component: https://reacttraining.com/react-router/web/api/Link
Get the router through props with the withRouter component, as explained in: Programmatically navigate using react router V4.
I have realized what I was doing wrong and was able to solve my issue.
The key was to understand that the Router module from react-router-dom
comes with three props : path , history, and component.
So in order to redirect a page on button click all I had to do embed all my Routes between tag in the App.js
APP JS
function App() {
return (
<Router>
<Switch>
<Route exact path="/test" component={componentA}/>
<Route exact path="/test2" component={componentB}/>
</Switch>
</Router>
);
}
export default App;
And then you can use button onClick to redirect
COMPONENTA JS
<button variant="secondary"
className="button" size="lg"
onClick={() => this.props.history.push('/test2')}>
RedirectTo
</button>
Hope this will be helpful to others who come across this!
In server.js file instead of button use navlink or link from reactrouter below is a saple code
<NavLink to="/control">control</NavLink>
Import every component to routing component then use router switch and redirect statements like below
import Main from './component/Main'
import Welcome from "./component/welcome"
import { Route, BrowserRouter as Router, Switch,Redirect } from 'react-router-dom'
function App() {
return (
<Router>
<Switch>
<Redirect from="/" to="/home" exact />
<Route exact path="/home" component={Main} />
<Route path="/welcome" component={Welcome} />
</Switch>
</Router>
);}
export default App;
and in your component where you re clicking import link or nav link i prefer using navlink
and use it to redirect to page on click
import { NavLink } from 'react-router-dom'
<NavLink to="/home">home</NavLink>

Combing React Router and Redux made my redirection KO

I have to combine use of Redux and React Router.
I tried react Router alone first and when I was clicking my images I was correctly redirected.
I followed redux tutorial and now when I click my images, I change the address (ex: http://localhost:3000/contact) but nothing displays as if the component was empty.
Root.js
import React from 'react';
import './index.css';
import PropTypes from 'prop-types'
import ReactDOM, { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'
import App from './App'
import Users from './users'
import Book from './Book'
import Notfound from './notfound'
import { Provider } from 'react-redux';
import Store from './redux/Store/store'
import * as serviceWorker from './serviceWorker';
const Root = ({ store }) => (
<Provider store = { Store }>
<Router>
<div>
<Switch>
<Route exact path="/:filter?" component={App} />
<Route path="/users" component={Users} />
<Route path="/book" component={Book} />
<Route path='/manual' component={() => { window.location = 'https://------'; return null;} }/>
<Route path='/contact' component={() => { window.location = 'https://-------'; return null;} }/>
<Route component={Notfound} />
</Switch>
</div>
</Router>
</Provider>
)
Root.propTypes = {
store: PropTypes.object.isRequired
}
serviceWorker.unregister();
export default Root
index.js:
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import myReducer from './redux/Reducers/myReducer'
import Root from './Root'
const store = createStore(myReducer)
render(<Root store={store} />, document.getElementById('root'))
App.js:
import React from 'react'
import { Route, Link, Redirect, withRouter, BrowserRouter as Router } from 'react-router-dom'
import logo from './images/logo.png';
import book from './images/book.png';
class App extends React.Component {
constructor() {
super();
this.state = {
date: new Date()
};
}
render() {
const { date } = this.state;
return (
<div>
<img src={logo} />
<img src={book} onClick={() => this.props.history.push('/book')}/>
<img src={call} onClick={() => this.props.history.push('/contact')}/>
</div>
)
}
}
export default App
Do you know what is wrong ?
A few things I noticed:
When using react router you shouldn't use window.location to redirect since this reloads the whole page. The <Redirect> component from react-router is a better choice here.
Also you shouldn't use the component prop on the <Route>-component for things that aren't actually components, as there's the render prop for that (more on that here).
Furthermore: <Route exact path="/:filter?" component={App} /> is not going to work since :filter? is looking for a variable and exact is looking for an exact match. Moreover you probably shouldn't put the flexible one first since it's going to match every route that you throw at it. So all the following routes are practically unreachable.

I use React Router 4 in React page but I can't see my component in Route path

[
import React, { Component } from "react";
import { BrowserRouter as Router , Route } from "react-router-dom";
const NewRout = () => {
return(
<p> MY ROUTE </p>
);
}
class App extends Component {
render() {
return (
<Router>
<Route path="/signin" Component={NewRout} />
</Router>
);
}
}
export default App;
]1I'm using router in my react page. But I can't see output.
I import BrowserRouter and Route from react-route-dom
and try to show mt component inside the route.but this is not working for me.Please help me how to solve this issue. Thanks
<BrowserRouter><Route path="signin" Component={Signin} /></BrowserRouter>
You have a mistake in your path:
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Link } from "react-router-dom";
import "./styles.css";
const Home = () => (
<h1>
Home <Link to="/signin">SING</Link>
</h1>
);
const SingIn = () => (
<h1>
<Link to="/">Home</Link>
This is singin page
</h1>
);
ReactDOM.render(
<div>
<BrowserRouter>
<div>
<Route exact path="/" component={Home} />
<Route path="/signin" component={SingIn} />
</div>
</BrowserRouter>
</div>,
document.getElementById("root")
);
Now locate to http://localhost:port/singin you will see your component.
Note: I added a / before your path. This denotes that you are going to signin from your root that is /.
You need to use a prop called exact which matches for exact Route.
Try this SandBox
https://codesandbox.io/s/moj8kxp0nx

React Router will not render Route component unless page is refreshed

It seems my application will not render the component passed to <Route /> unless I refresh the page. What could I be doing wrong?
components/App/index.jsx
// dependencies
import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom'
// components
import Header from '../Header';
// containers
import SidebarContainer from '../../containers/SidebarContainer';
import MainContainer from '../../containers/MainContainer';
const App = ({store}) => (
<Provider store={store}>
<Router>
<div className="wrapper">
<Header />
<div className="container-fluid container-fluid--fullscreen">
<div className="row row--fullscreen">
<SidebarContainer />
<MainContainer />
</div>
</div>
</div>
</Router>
</Provider>
);
App.propTypes = {
store: PropTypes.object.isRequired,
};
export default App;
containers/MainContainer.jsx
// dependencies
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Route } from 'react-router-dom'
// components
import Dashboard from '../components/Dashboard';
import List from '../components/List';
// containers
import LoginContainer from './LoginContainer.jsx'
class Main extends Component {
render() {
console.log(this.props)
return(
<div className="wrapper">
<Route exact path="/" component={Dashboard} />
<Route path="/login" component={LoginContainer} />
<Route path="/users" component={List} />
</div>
);
}
}
const mapStateToProps = (state) => {
return {
token: state.authentication.token,
};
};
const MainContainer = connect(mapStateToProps, null)(Main);
export default MainContainer;
So it seems when I click on a <Link to="/users" /> component my path changes to http://localhost:3000/users but the component does not change from Dashboard to List
I'm also noticing that when I console.log this.props from MainContainer I do not see anything related to router such as this.props.location.pathname --perhaps I'm not structuring my application correctly?
After poking around the react-router issues page on github I found this thread: https://github.com/ReactTraining/react-router/issues/4671
It appears as though the redux connect method blocks context which is required by react-router package.
That being said, the fix for this is to wrap all redux connected components that have router components inside with withRouter() like so:
containers/MainContainer.jsx
// dependencies
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom' // IMPORT withRouter
// components
import Dashboard from '../components/Dashboard';
import List from '../components/List';
// containers
import LoginContainer from './LoginContainer.jsx'
class Main extends Component {
render() {
console.log(this.props)
console.log(this.context)
return(
<div className="wrapper">
<Route exact path="/" component={Dashboard} />
<Route path="/login" component={LoginContainer} />
<Route path="/users" component={List} />
</div>
);
}
}
const mapStateToProps = (state) => {
return {
token: state.authentication.token,
};
};
// WRAP CONNECT METHOD
const MainContainer = withRouter(connect(mapStateToProps, null)(Main));
export default MainContainer;
I think you have to do little more tweak in your code to make it work. Assuming you use react-router v4, the following should solve your problem.
import { BrowserRouter, Route, Switch } from 'react-router-dom';
<Provider store={store}>
<BrowserRouter>
<div>
<Switch>
<SidebarContainer />
<MainContainer />
</Switch>
</div>
</BrowserRouter>
</Provider>

Resources