React-Router nested routes names - react-router-v4

I would like to implement that kind of routes in react-router v4.
/auth => auth home page
/auth/login => login page
/auth/register => register page
/auth/forgot => lost password page
/auth/reset => change password page
It doesn't work with <Switch> because it first match /auth and render the associated component. So as I click on the link to go to the login page for instance it renders the Auth Component and not the Login Component.
How can I implement that behavior with react-router ?
I tried nested routing but if I take the same example as before, It would renders the Auth Component + Login Component.
Thanks.

You can add the exact prop to your /auth route:
<Switch>
<Route exact path='/auth' component={Auth} />
<Route path='/auth/login' component={Login} />
<Route path='/auth/register' component={Register} />
<Route path='/auth/forgot' component={ForgotPassword} />
<Route path='/auth/reset' component={ChangePassword} />
</Switch>
Alternatively, you could move your /auth route to the end of the list so other routes match first:
<Switch>
<Route path='/auth/login' component={Login} />
<Route path='/auth/register' component={Register} />
<Route path='/auth/forgot' component={ForgotPassword} />
<Route path='/auth/reset' component={ChangePassword} />
<Route path='/auth' component={Auth} />
</Switch>
I hope this helps.

Related

Can't get ReferenceManyField to display data

Have spent several hours trying to get ReferenceManyField to display some data in a nested DataGrid.
<Show {...this.props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="name" />
{/* THE FOLLOWING COMPONENT DOES NOT DISPLAY ANY DATA. WHY NOT??? */}
<ReferenceManyField label="Stores" reference="stores" target="companies_id">
<Datagrid rowClick="show">
<TextField source="id" />
<TextField source="storeName" />
</Datagrid>
</ReferenceManyField>
</SimpleShowLayout>
</Show>
I have created a massively stripped down version of my app, which demonstrates the problem:
https://codesandbox.io/s/react-admin-referencemanyfield-issue-forked-lde6c
I am certain there has to be a simple explanation for this issue, but as a relative newcomer to React/ReactAdmin/Typescript I just can't see it. What am I doing wrong?
Grateful for any tips & advice.
You haven't declared the stores resource in your Admin component.
Add a <Resource name="stores" /> inside Admin

Re render Header in ReactJs

I have index.js as below code:
<relevant imports>
function Header(){
return(<HeaderComponent/>);
}
ReactDOM.render(
<div>
<Router>
<div>
<Switch>
<Route path="/page1" component={page1} />
<Route path="/page2" component={page2} />
<Route path="/page3" component={page3} />
<Route path="/home" component={PortfolioPageComponent} />
<Route path="/" component={WelcomePage} />
</Switch>
</div>
</Router>
</div>,
document.getElementById('root')
);
ReactDOM.render(<Header />, document.getElementById('page-header'));
now when I am opening my app it goes to WelcomePage .In this component I have authorization logic. once Authetication is done, Page is redirecting to PortfolioPageComponent but header component is NOT getting reloaded.
How can I re-render Header component also on each redirection?
Putting the header component OUTSIDE the switch component allows it to render with each route. This way, no matter which route you navigate to, the components outside of the switch will always be rendered. This could be including a header before the switch component and a footer afterwards.

Injecting List, Show, Edit, Create in any places

I would like create a file browser with <List /> component in <Show /> component.
Let's say we have a user with home directory and we want to create a file browser to this directory with ability to remove files. The idea of files doesn't match the idea of simple tables, which rows can be edited.
So I have created my own component with username and directory as states, useDataprovider() as hook, and <Table/> from MUI, altered data provider a bit. And it works quite nice.
The problem comes when there are many position in list, like 50+. A pagination would be nice. So I tried to fake props of <List /> and later <ListView /> to replace <Table /> but I failed.
After short code review, it looks like implementing <List /> as is, is not possible, because many hooks and other things it uses. In general nesting one into another of any type would be a mess in come.
My idea of this would look like this:
function HomedirBrowser({username}) {
const [usrPath, setUsrPath] = React.useState("/");
return (<List
resource={`/users/${username}/dir/${usrPath}`}
>
<Datagrid>
<TextField source="type"/>
<TextField source="name"/>
<TextField source="last_edit"/>
<TextField source="size"/>
<Button onClick={({record}) => setUsrPath(usrPath + "/" + record.name)}>Enter</Button>
</Datagrid>
</List>)
}
The custom resource which would depend on a state and the button could alter the state.
Is this possible to do? Or there is any other way to achieve nesting one element into another.
Of course, I don't want to save state to browsing in url of anywhere at all.
I had a similar problem. I wanted to place a List component inside a Show component. Here is an example what I wanted to achieve:
const AuthorShow = props => (
<Show {...props}>
<TabbedShowLayout>
<Tab label='author'>
<TextField source="firstName"/>
<TextField source="lastName"/>
</Tab>
<Tab label='books'>
<List {...props}
resource='books'
filter={{authorId: props.id}}>
<Datagrid>
<TextField source="title" />
</Datagrid>
</List>
</Tab>
</TabbedShowLayout>
</Show>)
Although I explicitly passed 'resource' prop, it was ignored and Show resource was used - authors. I managed to fix this behavior by wrapping List in a Fragment.
const AuthorShow = props => (
<Show {...props}>
<TabbedShowLayout>
<Tab label='author'>
<TextField source="firstName"/>
<TextField source="lastName"/>
</Tab>
<Tab label='books'>
<Fragment>
<List {...props}
resource='books'
filter={{authorId: props.id}}>
<Datagrid>
<TextField source="title" />
</Datagrid>
</List>
</Fragment>
</Tab>
</TabbedShowLayout>
</Show>)
I don't know what caused that you failed to use List but this one may give you some clue at least.
I have the similar code:
<Fragment>
<List
{...props}
resource="card_program_options"
filterDefaultValues={{ card_id: 1 }}
sort={{ field: "id", order: "ASC" }}
>
<Datagrid>
<TextField source="card_id" />
<TextField source="card_programs_id" />
</Datagrid>
</List>
</Fragment>
But the only thing i see on the page is No results found
screenshot of No results found in show
I see the request made in the backend and completes with a 200 response code.
Help is appreciated!

Routing from outside of a Route component

I have an app where i'm using react router and I can't figure out how to change the route in this use case. Here's how my code is structured:
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
<Router>
<Panels />
<Route path="/view" render={()=> <MyComponent />} />
<Route path="/about" render={()=> <MyOtherComponent />} />
</Router>
Inside <Panels> are some tabs I have that I would like to change the route.
<Tabs defaultActiveKey="1" onChange={}>
<TabPane tab="Tab 1" key="1" >
<Somecomponent />
</TabPane>
<TabPane tab="Tab 2" key="2">
Test me
</TabPane>
</Tabs>
These are antd tabs so they don't have a clickable component that I can put a <Link> into, and <Panels> is outside of a <Route> so I'm not sure if I'm able to access history object otherwise. I could put the panels in each <Route> but that would be really bad.
What way should I go about this?
Figured this one out finally.
import { withRouter } from 'react-router-dom'
...
<Tabs defaultActiveKey="1" onChange={(key)=> this.props.history.push(`/${key}`)}>
<TabPane tab="Tab 1" key="1" >
<Somecomponent />
</TabPane>
<TabPane tab="Tab 2" key="2">
Test me
</TabPane>
</Tabs>
...
export default withRouter(Panels);
wrapping the export with withRouter give the component access to the history object to push and read routes. I saw this solution initially but couldn't get it to work. Turns out it was because I was importing withRouter from react-router and not react-router-dom, so I was loading in the wrong history.

react-router v4 : how do you handle "/" page as synonym for other page?

I have a server that renders the same single page app for multiple URLS :
/
/A
/B
I want A to act as a "Home" page.
So a browser request to "/" or "/A" should display the same thing.
In particular, I'll have links to pages A and B, and I want the link to A to be marked as active for "/" and "/A".
So I'm using something like :
<NavLink to="/A" activeClassName='nav-active'>Go to A</NavLink>
<NavLink to="/B" activeClassName='nav-active'>Go to B</NavLink>
<Router>
<Route path='/A' component={A} />
<Route path='/B' component={B} />
</Router>
How would I make "/" as a synonym for "/A" ? What I tried :
adding another Route with path="/" : this results in two components being displayed
using a regexp like path="/(A)?" : this displays the right component, but the link ist not marked as active
Should I implement it as a server side redirect instead (just making / redirect to /A rather than serving the same page content ?)
It seems like a Redirect does the trick
<Router>
<Route path='/A' component={A} />
<Route path='/B' component={B} />
<Route path='/' render={() => (
<Redirect to='/A' />
)} />
</Router>
You can add exact={true}
<Router>
<Route path='/' exact={true} component={A} />
<Route path='/A' exact={true} component={A} />
<Route path='/B' exact={true} component={B} />
</Router>