ConnectedRouter from react-router-redux does not support children props - react-router-v4

While
<Router history={browserHistory} children={this.props.routes} />
is supported in React router v4,
using react-router-redux ConnectedRouter does not support it
for example
<ConnectedRouter
history={this.props.history}
children={this.props.routes}
/>
is there a way to pass routes as children props, since this is easy way to build routes with objects
Thanks

you should crete your app component inside
<ConnectedRouter history={history}>
<div>
<App />
</div>
</ConnectedRouter>
your app component should handle the child components with the switch and Route elements,
something like :
<Switch> {/* redirect to the first correct statemet */}
<Route path={NavigationPath.Home} component={Home} />
<Route path={NavigationPath.About} component={About} />
<Route path={NavigationPath.Summary} component={Summary} />
<Route path={NavigationPath.Account} component={Login} />
<Redirect from="/" to={NavigationPath.Home} />
<Route component={NotFound} />
</Switch>
than you have child components with routes

you could map the object to components like they do in the docs:
////////////////////////////////////////////////////////////
// then our route config
const routes = [
{ path: '/sandwiches',
component: Sandwiches
},
{ path: '/tacos',
component: Tacos,
routes: [
{ path: '/tacos/bus',
component: Bus
},
{ path: '/tacos/cart',
component: Cart
}
]
}
]
// wrap <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = (route) => (
<Route path={route.path} render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes}/>
)}/>
)
const RouteConfigExample = () => (
<Router>
<div>
<ul>
<li><Link to="/tacos">Tacos</Link></li>
<li><Link to="/sandwiches">Sandwiches</Link></li>
</ul>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route}/>
))}
</div>
</Router>
)
From here: https://reacttraining.com/react-router/web/example/route-config

Related

Why does react router work on localhost but will not work after Heroku deployment?

there are a few posts like this and I have tried other solutions such as adding a .htaccess file, and adding 'process.env.PUBLIC_URL' ahead of each route to get the relative route location, but nothing seems to be working with the new react-router-dom package which has been released...
The application will load the '/' login page no problem on startup in heroku, and in there a direct will move to another page, however after successful login I use 'window.location.assign("/Home")' to try to auto navigate back to the home page. This gets a 404 error.
Similarly, manually adding locations into the top bar also give 404 errors..
I have tried the fixes provided in other posts, but they are all for the old react-router-dom package (before they moved away from switch and started using BrowserRouter).
Can anyone help figure out why my router won't identify addresses added to the window location??
The application is currently deployed at https://dashboard.heroku.com/apps/octowatch-scratch
App.js
import React from "react";
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { createTheme, ThemeProvider } from '#mui/material/styles';
import AboutKPI from './pages/AboutKPI';
import Login from './pages/Login';
import BreachComposition from './pages/BreachComposition';
import BreachesPerWard from './pages/BreachesPerWard';
import Dashboard from './pages/Dashboard';
import AddAccount from './pages/AddAccount';
import ManageAccounts from './pages/ManageAccounts';
import OverallBreaches from './pages/OverallBreaches';
import AddData from './pages/AddData';
import Home from './pages/Home';
import { lightGreen, brown } from '#mui/material/colors';
import './App.css';
const theme = createTheme({
palette: {
primary: {main: lightGreen[900]},
secondary: {main: brown[500]},
},
});
function App() {
return (
<BrowserRouter>
<ThemeProvider theme={theme}>
<Routes>
<Route exact path="/" element = {<Login/>} />
<Route exact path="/AboutKPI" element = {<AboutKPI/>} />
<Route exact path="/BreachComposition" element = {<BreachComposition/>} />
<Route exact path="/BreachesPerWard" element = {<BreachesPerWard/>} />
<Route exact path="/Login" element = {<Login/>} />
<Route exact path="/Home" element = {<Home/>} />
<Route exact path="/Dashboard" element = {<Dashboard/>} />
<Route exact path="/AddAccount" element = {<AddAccount/>} />
<Route exact path="/ManageAccounts" element = {<ManageAccounts/>} />
<Route exact path="/OverallBreaches" element = {<OverallBreaches/>} />
<Route exact path="/AddData" element = {<AddData/>} />
</Routes>
</ThemeProvider>
</BrowserRouter>
);
}
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Login Page ()
import React, { useState } from "react";
import { Grid,Paper, Avatar, TextField, Button, Typography } from '#mui/material'
import FormControlLabel from '#mui/material/FormControlLabel';
import Checkbox from '#mui/material/Checkbox';
import Api from "../api.js"
import LockIcon from '#mui/icons-material/Lock';
import { Link } from 'react-router-dom';
export default function Login(breachesCallback) {
const paperStyle={padding :20,height:'70vh',width:280, margin:"20px auto"}
const avatarStyle={backgroundColor:'#1bbd7e'}
const btnstyle={margin:'8px 0'}
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
var now = new Date();
function validateForm() {
return email.length > 0 && password.length > 0;
}
function goHome () {
window.location.assign("/Home");
}
function goReset () {
window.location.assign("/UpdatePassword");
}
function handleSubmit(event) {
Api.noToken().post('/users/login', {
email: email,
password: password,
resetDate: Math.floor(((now / 8.64e7) - 150.604166666))
})
.then(function (response) {
if(response.status === 204){//this means a password reset still needs to occur here
Api.withToken().get('/breaches/')
.then(res => {
breachesCallback(res.data);
console.log(res.data);
}).then(goReset());
}
else if(response.status === 200){
window.sessionStorage.setItem("token", response.data.token);
Api.withToken().get('/breaches/')
.then(res => {
breachesCallback(res.data);
console.log(res.data);
}).then(goHome());
}
})
.catch(function (error) {
alert("Invalid username or password")
});
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<Grid>
<Paper elevation={10} style={paperStyle}>
<Grid align='center'>
<Avatar style={avatarStyle}><LockIcon/></Avatar>
<h2>Sign In</h2>
</Grid>
<TextField label='Username' placeholder='Enter username' fullWidth required onChange={e => setEmail(e.target.value)}/>
<TextField label='Password' placeholder='Enter password' type='password' fullWidth required onChange={e => setPassword(e.target.value)}/>
<FormControlLabel
control={
<Checkbox
name="checkedB"
color="primary"
/>
}
label="Remember me"
/>
<Button type='submit' disabled={!validateForm()} color='primary' variant="contained" style={btnstyle} fullWidth>Sign in</Button>
<Typography >
<Link to="#" >
Forgot password ?
</Link>
</Typography>
<Typography > Do you have an account ?
<Link to="/AddAccount" >
Sign Up
</Link>
</Typography>
</Paper>
</Grid>
</form>
)
}
After hours of looking I've finally found the most up to date tool you are meant to use for react router in the latest update (currently 6.1.1)
This is about 3 posts down in this post (the other answers are all for older versions of react router and will not work)
The answer is simple:
import { useNavigate } from "react-router-dom";
then in your function add a simpler variable for useNavigate:
let navigate = useNavigate();
and replace your window.location.assign("/Home") with navigate("/Home", { replace: true });
(obviously could also just say useNavigate("/Home", {replace:true})

Creating new record does not register in list without refresh and creates duplicate record

Below is a screenshot of the Redux dev tools. This is a list of records of a particular resource. As you can see, the newly added record has a duplicate with the key undefined. It also does not register on the list without a refresh.
Redux Dev Tools
Here is the create component:
export const OrgCreate = (props: ReactAdminComponentProps) => {
const controller = useCreateController(props);
return (
<Create {...props} {...controller}>
<SimpleForm>
<TextInput source="name" />
</SimpleForm>
</Create>
);
};
Here is the list component:
export const OrgList = (props: ReactAdminComponentProps) => {
const controller = useListController(props);
return (
<List {...props} {...controller} exporter={false} bulkActionButtons={false}>
<Datagrid rowClick="edit" hasBulkActions={false}>
<TextField source="name.value" label="Name" />
<DateField source="createdAt" />
</Datagrid>
</List>
);
};
Here is the create response in the GraphQL provider:
createResponse = (data: any) => data.createOrganization.organization;
Try removing the lines:
const controller = useCreateController(props);
const controller = useListController(props);
and further {...controller}, it should work.

React Router v4 - Redirect

I'm trying to get React-Router v4 up but i'm running into some difficulty. I can create routes and test them in the browser and they resolve correctly, however if i try to direct someone to a route programatically i run into problems.
The redirect should happen after the user has clicked on a row in a table, i can see the onClick works fine (so i know the callback is working) but the redirect doesn't work...any ideas?
import { Redirect } from 'react-router-dom';
export default class Table extends Component {
...
...
onClick(foo) {
// let path = `/booking/${foo.bar}`;
// console.log(path);
// <Route path="/booking" render={() => <BookingForm />}/>;
<Redirect to='/booking' />;
}
...
...
}
My Routes are:
const Routes = () => (
<main>
<Switch>
<Route exact path='/' component={HomePage} />
<Route exact path='/cruises' component={Cruises} />
<Route exact path='/booking' component={BookingForm} />
</Switch>
</main>
);
Thanks
I think below code should solve your problem.
import { withRouter } from 'react-router-dom';
class Table extends Component {
...
...
onClick(foo) {
let path = `/booking/${foo.bar}`;
this.props.history.push(path);
}
...
...
}
export default withRouter(Table);

pass user prop to all children react router

I want to write a wrapper component that passes any children props. For example in a pure react auth system.
<Router history={ hashHistory } >
<Route path="/" component={Base}>
<Route component={Auth}>
<Route path="/who" component={Who} />
<Route path="/features" component={Features} />
<Route path="/try" component={Try} />
</Route>
</Route>
</Router>
I want to pass a user by props to either the Who, Features or Try components from Auth, which will pull from local storage.
The silly thing I have tried to do is to manipulate this.props or this.props.children but this is not ok, what is the recommended solution?
class Auth extends Component {
render() {
//find user or null
var user = JSON.parse(localStorage.getItem('user')) || [];
//this.props.user = user;
console.log('top level router props.user', this.props.user);
return (
<div>
{this.props.children}
</div>
);
}
}
see this answer by Jess. React clone element is what you want.
React router and this.props.children - how to pass state to this.props.children
render() {
var childrenWithProps = React.cloneElement(this.props.children, {someProp: this.state.someProp});
return (
<div>
<Header />
{childrenWithProps}
</div>
);
}
If you upgrade to version 4 you can use Match with your own HOC for auth.
https://react-router.now.sh/auth-workflow

Server-side rendering(express) with react router does not work

I am trying server-side rendering using node js, React, Redux and React-Router.
I followed react-router server-side tutorial but I am only getting root route, no matter what route I put. As you see in the routes.js, I have a route to detail.
I tried path="detail" as well
and Link is like below
<Link to="/detail"> Detail</Link>
When I click that link, it does not even give me error like "no matched route to /detail".
If you want to see all codes - git repo
Here is my code
routes.js
export default ([
<Route path="/" component={App}>
<Route path="/detail" component={DetailView}/>
</Route>
]);
server.js
app.get('/*',(req,res)=>{
match({ routes:routes, location: req.url }, (error, redirectLocation, renderProps) => {
if (error) {
res.status(500).send(error.message)
} else if (redirectLocation) {
res.redirect(302, redirectLocation.pathname + redirectLocation.search)
} else if (renderProps) {
const store = createStore(Reducers);
const html = renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
);
res.status(200).send(renderFullPage(html, store));
} else {
res.status(404).send('Not found')
}
})
});
renderFullPage - this basically injects html from rederToString to html string
<div id="app">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState)}
</script>
client.js(index.js)
const history =createBrowserHistory();
match({ history, routes }, (error, redirectLocation, renderProps) => {
ReactDom.render(
<Provider store={store} >
<Router {...renderProps} />
</Provider> , document.getElementById('app'))
});
App.js
class App extends React.Component {
render() {
return (
<div>
<div className="container">
<PokemonContainer />
</div>
</div >
)
};
}
Thank you for look into it and please give me any opinion about this.
Try removing the leading slash:
export default ([
<Route path="/" component={App}>
<Route path="detail" component={DetailView}/>
</Route>
]);
No sure if that's the issue with routing but you have to pass store state to renderFullPage not the store itself. So it should be something like this:
} else if (renderProps) {
const store = createStore(Reducers);
const initialState = store.getState()
const html = renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
);
res.status(200).send(renderFullPage(html, initialState));
}