Routing from outside of a Route component - react-router-v4

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.

Related

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!

How to use <ios> or <android> elements in Nativescript Vue

I would like to do this
```xml
<android>
<NavigationButton
text="Go Back"
android.systemIcon="ic_menu_more"
#tap="$refs.drawer.nativeView.showDrawer()"/>
</android>
<ios>
<ActionItem
text="Menu"
#tap="$refs.drawer.nativeView.showDrawer()" />
</ios>
</ActionBar>
```
What is the best way to go about it ?
As posted here https://github.com/nativescript-vue/nativescript-vue/issues/180#issuecomment-380844535
You can use these elements like you did, but the ActionBar is a bit different (hence why it doesn't work as you'd expect). What I've done in a project was to add
// main.js
import { isAndroid, isIOS } from 'tns-core-modules/platform';
Vue.prototype.$isAndroid = isAndroid;
Vue.prototype.$isIOS = isIOS;
In template
<ActionBar android.icon="ic_home" class="action-bar" title="Home">
<NavigationButton
v-if="$isAndroid"
text="Go Back"
android.systemIcon="ic_menu_more"
#tap="$refs.drawer.nativeView.showDrawer()"/>
<ActionItem
v-else
text="Menu"
#tap="$refs.drawer.nativeView.showDrawer()" />
</ActionBar>

React-Router nested routes names

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.

How to styling header & button with StyleProvider at the same page?

I've struggling for two days to styling components on Native Base with <StyleProvider>. I want to change background color of header and add custom style property on the button.
<Container>
<Header /> /*change backgroundColor*/
<Content>
<Button viewDetail block> /*add 'viewDetail' as custom style property */
<Text>Button</Text>
</Button>
</Content>
</Container>
I think, I have the answer for my own question.
Import all components from 'native-base-theme/components/' instead of variables.
The code will be like this
import getTheme from './native-base-theme/components';
and add <StyleProvider>, then add prop style <StyleProvider style={getTheme()}>.
There are many ways of doing this. One way would be to follow the instructions given here. Alternatively, you can change the button theme file and add a similar style property like success shown here.
I hope this will help you,
You must be using NativeBase2
<StyleProvider style={getTheme(commonColor)}>
<Header>
<Left>
<Button transparent>
<Icon name="arrow-back" onPress={() => this.props.routerActions.pop()} />
</Button>
</Left>
<Body>
<Title>Profile</Title>
</Body>
<Right></Right>
</Header>
</StyleProvider>
For ejecting theme,
Just open this link and follow
http://nativebase.io/docs/v2.0.0/customize#themingNativeBaseApp
Now If you want to customise just look for
native-base-theme/components/Header.js
native-base-theme/variables/commonColor.js