When using history.push the following screen is not rendered - javascript

When changing the screen, using history.push the new screen is not loaded.
I've seen some posts about it, but no solution has actually helped.
ReactDOM.render(
<Router history={history}>
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>
</Router>,
document.getElementById('root')
);
Above is my main component, where I use redux
const isLogged = localStorage.getItem('user')
const PrivateRoute = (props) => {
return isLogged ? <Route {...props} /> : <Redirect to="/login" />
}
const App = () => {
return (
<MuiThemeProvider theme={theme}>
<div className="container-fluid p-0" style={{ backgroundColor: 'rgba(0,0,0,0.2)', }}>
<Switch>
<Route exact path='/login' component={Login} />
<PrivateRoute exact path="/" component={Dashboard} />
</Switch>
<AlertComponent />
</div>
</MuiThemeProvider>
);
}
Here is my component of routes where I have the login screen and the main screen of my application.
const authenticate = () => {
setLoading(true)
UserService.login(email, password, (response) => {
setLoading(false)
response.error ?
dispatch(createAlertError('Email e/ou senha inválida'))
:
dispatch(userSignInSuccess(response.user.shift()))
history.push('/')
})
}
Here in my login component, when calling this function the route changes, but the new component is not updated.
Here is the repository link

There are some issues in your code which you can correct
In your main component don't wrap Provider with <Router>, wrap in <Provider />, in that way route handlers can get access to the store. To know more click
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);
In your App.js use <Router> and no need to inject history object there, when you're using react router, connected component will have access to it.
Like the <PrivateRoute> create one more component as <PublicRoute> which will do the exact opposite check of <PrivateRoute>
const isLogged = localStorage.getItem('user')
const PrivateRoute = (props) => {
return isLogged ? <Route {...props} /> : <Redirect to="/login" />
}
const App = () => {
return (
<MuiThemeProvider theme={theme}>
<div className="container-fluid p-0" style={{ backgroundColor: 'rgba(0,0,0,0.2)', }}>
<Router>
<Switch>
<Route exact path='/login' component={Login} />
<PrivateRoute exact path="/" component={Dashboard} />
</Switch>
</Router>
<AlertComponent />
</div>
</MuiThemeProvider>
);
}
Try above steps and let me know your progress, Thanks

const authenticate = () => {
setLoading(true)
UserService.login(email, password, (response) => {
setLoading(false)
response.error ?
dispatch(createAlertError('Email e/ou senha inválida'))
:
dispatch(userSignInSuccess(response.user.shift()), history.push('/'), history.go(0))
})
}
history.go(0) to render the page again

Related

Creating routes inside a private route with react-router v6

Currently using react-router-dom 6.1.1 and I'm working with a private route.
Inside this private route I usually had other routes (so that I can keep my Sidebar on them).
My code looks like this
// App.tsx
const RequireAuth: React.FC<PrivateRouteProps> = ({ children, redirectTo }) => {
const isAuthenticated = Auth.isLogedIn()
return isAuthenticated ? children : <Navigate to={redirectTo} />
}
const Page = () => {
return (
<div className={css.host}>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path="/"
element={
<RequireAuth redirectTo="/login">
<Home />
</RequireAuth>
}
/>
</Routes>
</BrowserRouter>
</div>
)
}
// Home/index.tsx
const Home = () => {
return (
<div className={css.host}>
<Sidebar sections={sidebarOptions(t)} />
<Routes>
{routes.map(({ breadCrumbtitle, link, component }, index) => (
<Route path={link} key={index}>
{component ? component : <p>[{breadCrumbtitle}] To be done</p>}
</Route>
))}
</Routes>
</div>
)
}
So... This setup worked with v5 but it seems to be something that doesn't really work with v6.
What can I do if I still want to keep the Sidebar for all the routes once I'm logged in?
I ended up finding the solution to my issue.
Doing what Drew Reese suggested only worked to a certain point since I was being led to a route that, for react router, didn't exist.
For it to work I add to do
// App.tsx
const RequireAuth: React.FC<PrivateRouteProps> = ({ children, redirectTo }) => {
const isAuthenticated = Auth.isLogedIn()
return isAuthenticated ? children : <Navigate to={redirectTo} />
}
const Page = () => {
return (
<div className={css.host}>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route
path=""
element={
<RequireAuth redirectTo="/login">
<Home />
</RequireAuth>
}
>
{routes.map(({ breadCrumbtitle, link, component }, index) => {
return <Route path={link} key={index} element={component}></Route>
})}
</Route>
</Routes>
</BrowserRouter>
</div>
)
}
// Home/index.tsx
const Home = () => {
return (
<div className={css.host}>
<Sidebar sections={sidebarOptions(t)} />
<div className={css.contentContainer}>
<Outlet />
</div>
</div>
)
}
Using the Outlet seemed to be essential, don't know if it's something new on react router v6 but seemed to do the trick!
As far as I can tell the only issue is with the routes mapping, the Route components have invalid children, i.e. you are rendering another Route or React.Fragment as a child.
Move this up to the element prop of the mapped Route components.
const Home = () => {
return (
<div className={css.host}>
<Sidebar sections={sidebarOptions(t)} />
<Routes>
{routes.map(({ breadCrumbtitle, link, component }, index) => (
<Route
path={link}
key={index}
element={component || <p>[{breadCrumbtitle}] To be done</p>}
/>
))}
</Routes>
</div>
);
};

React Conditional rendering doesn't show anything

React app with react-router-dom: 4.3.1:
Main App.js render:
render() {
let routes = (
<Switch>
<Route component={LogIn} path="/login" />
<Redirect to="/login" />
</Switch>
);
if (this.props.isAuthenticated) {
routes = (
<Switch>
<Route component={ParcelListView} path="/" exact />
<Route component={StatusTable} path="/status" />
<Redirect to="/" />
</Switch>
);
}
return (
<div className="app">
{routes}
</div>
);
}
I see white screen When use this code, but when I assign to routes first or second Switch without if it works perfectly in both cases.
I guess the problem comes from assignment in if block. Is this some kind of async thing?
You might want to set routes inside of a <Switch /> component whatever the scenario and have either public or private route components. Here is a common approach:
const PublicRoute = ({
isAuthenticated,
component: Component,
...rest
}) => (
<Route
{...rest}
component={props => (
isAuthenticated ? (
<Redirect to="/somewhere" />
) : (
<Component {...props} />
))}
/>
);
const PrivateRoute = ({
isAuthenticated,
component: Component,
...rest
}) => (
<Route
{...rest}
component={props => (
isAuthenticated ? (
<div>
<Header />
<Component {...props} />
</div>
) : (
<Redirect to="/login" />
)
)}
/>
);
Both components take component (function) and isAuthenticated(boolean) as props and we pass the rest of the props down ({...rest}) anyway (path etc.)
This way you're able to allow/deny routes based on the propspassed down to your components:
...your code
render() {
<Switch>
<PublicRoute path="/" component={YourPublicComponent} />
<PrivateRoute path="/" isAuthenticated component={ParcelListView} />
</Switch>
}
More at Tyler McGinnis's website: https://tylermcginnis.com/react-router-protected-routes-authentication/
Another post on the subject: https://medium.com/#tomlarge/private-routes-with-react-router-dom-28e9f40c7146
You'll be able to find a lot of stuff on the subject on the web

Objects are not valid as a React child using react router v4

This is my wrapper component aka auth component to allow only authed user to access.
Auth.js
render() {
const { Component: component, ...rest } = this.props;
return (
<Route>
{rest}
render={props =>
this.isAuth === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login"
}}
/>
)
}
</Route>
);
}
What's wrong with it? Here's my route declaration
Index.js
render(
<BrowserRouter>
<div className="App">
<Switch>
<Route path="/login" component={Login} />
<Auth path="/dashboard" component={Dashboard} />
</Switch>
</div>
</BrowserRouter>,
document.getElementById("root")
);
I've made a demo to reproduce the problem here
https://codesandbox.io/s/5xm202p1j4
I used the same concept in the official doc, https://reacttraining.com/react-router/web/example/auth-workflow just that instead of making the auth.js a pure function I make it a class base container so that I can call api or check the token of the user exist or not in my localstorage, what's the problem exactly?
Did you mean to do something like this:
render() {
const { Component: component, ...rest } = this.props;
return (
<Route
{...rest}
render={props =>
this.isAuth === true ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login"
}}
/>
)
}
/>
);
}
By having rest and render in the <Route> tag so the rest are passed to the <Route>?

React with Redux and Router - not rendering component

I don't understand why component Sample is not rendering at all. Url changes, no errors in console, however component is not mounted. No matter if it is functional component or React class. And why inline component with URL "/thisworks" is rendered properly. What am I doing wrong here?
index.jsx:
render(
<Provider store={store}>
<Root />
</Provider>,
document.getElementById("root")
);
root.js:
const Root = () => (
<div>
<BrowserRouter>
<Switch>
// routes below work fine
<Route path="/login" component={LoginPage} />
<Route path="/" component={App} />
</Switch>
</BrowserRouter>
<DevTools />
</div>
)
App.js:
class App extends React.Component {
render() {
return (
<div>
<NavMenu />
<Switch>
<Route path="/thisworks" render={(props) => {
return (<div>This works!</div>);
}} />
<Route path="/sample" Component={Sample} /> // not working - not rendering component Sample
<Redirect from="/" to="/sample" />
</Switch>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => ({})
const mapDispatchToProps = (dispatch) => ({})
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App))
Sample.jsx:
const Sample = (props) => {
return (
<div>
Sample!
</div>
);
}
export default Sample;
Maybe component instead of Component?
<Route path="/sample" component={Sample} />

How can i authorize a route in react with redux?

Here I want that only loggedin user should be able to open the profile route. What is the best way to do it?
main.js
let store = createStore(todoApp, applyMiddleware(thunkMiddleware));
render(
<Provider store={store}>
<Router history={browserHistory}>
<div className="container">
<Route exact path="/" component={Login}/>
<Route path="/profile" component={Profile} />
</div>
</Router>
</Provider>,
document.getElementById('root')
)
You could do somthing like :
<Route path="/profile" component={RequiresAuth(Profile)} />
And create a authentication function like :
function RequiresAuth(ComposedComponent) {
class Authenticate extends Component {
render() {
if (!userAuthenticated) { // Check if user is authenticated
return null;
} else {
return (
<ComposedComponent {...this.props} />
);
}
}
}
}

Categories