Why can't I hit my nested route? ReactRouter4 - react-router-v4

I am trying to hit a nested Route, but for some reason it is not hitting the Component's render function. Here is my route file:
const routes = (
<Route path="/financefe" render={() => (
<Normalize>
<Switch>
<Route path="/test" component={Test} />
</Switch>
</Normalize>
)}/>
);
When I go to localhost:3000/financefe, I hit the render function. The Normalize components is rendered. I then try to go to localhost:3000/financefe/test, but the Test component does not get hit. What am I missing? Why isn't this working?

react-router v4 route paths must be absolute. here's an example taken from this article, under the section named "Nested Routes":
const Main = () => (
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>
</main>
)
const Roster = () => (
<Switch>
<Route exact path='/roster' component={FullRoster}/>
<Route path='/roster/:number' component={Player}/>
</Switch>
)

Related

react navigation, get name of nested route

I have a nested drawer navigator below, I am using a custom component in the header:
header: props => {
return <DrawerHeader {...props} />;
},
When I try and access from props the current route in my header, like below, the title is undefined, how can I get the current route?
render() {
const {
navigation,
videos,
search: {term},
scene: {
route: {routeName: title}, // undefined
},
} = this.props;
return (
<View>
<View style={styles.container}>
Navigator:
function DrawerStack() {
return (
<Drawer.Navigator>
<Drawer.Screen
name="VideoEpisodesScreen"
component={VideoEpisodesScreen}
/>
<Drawer.Screen name="TestYourselfScreen" component={TestYourselfScreen} />
<Drawer.Screen name="MyResultsScreen" component={MyResultsScreen} />
<Drawer.Screen name="AboutScreen" component={AboutScreen} />
<Drawer.Screen name="TestsScreen" component={TestsScreen} />
<Drawer.Screen
name="BookmarkedVideosScreen"
component={BookmarkedVideosScreen}
/>
</Drawer.Navigator>
);
}
export default function AppNavigator() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={stackOptions}
/>
<Stack.Screen
name="Drawer"
component={DrawerStack}
options={drawerOptions}
/>
<Stack.Screen
name="MyResultsScreen"
component={MyResultsScreen}
options={options}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
Funnily enough I had the exact same problem and I found your question after it was just an hour old. Essentially the problem is that React Navigation will only give you the current route of the navigator containing the header. If you have a nested navigator, you won't be able to get it.
It looks like this is somewhat intentional, but I've found that by manually querying the state of the navigator, you can drill down to the "deepest" navigator route. Note that while this works for react-navigation 5, it may not work in the future.
You can iteratively query the nested state like this:
const state = navigation.dangerouslyGetState();
let actualRoute = state.routes[state.index];
while (actualRoute.state) {
actualRoute = actualRoute.state.routes[actualRoute.state.index];
}
Note that this is extremely brittle, but it seems to work good enough for my use cases. You should consider creating an issue/feature request on the react-navigation repository for supporting this use case officially.
React Navigation v6 solution:
A nested route object can be discovered through parent Screen listeners. It's given in a callback argument, and can be passed to getFocusedRouteNameFromRoute to get the route name. In the example shown below, I chose to utilize it during the event 'state' (whenever state changes in the nested stack), but you can use it elsewhere if you want.
<Screen
listeners={({ route }) => ({
state: () => {
const subRoute = getFocusedRouteNameFromRoute(route)
// Your logic here //
}
})}
/>
I think in react-navigation 5, you can access route from this.props
const { route } = this.props;

IntialParams on a Tab Navigator Screen is undefined (react navigation v5)

I'm trying to pass an initialParam prop to a TabNavigator screen. It is meant to be a login piece of local state, just doing a proof of concept. It works fine with the stack navigator screen, but the route.params on the tab screen is undefined. What am I doing wrong?
Also, I'm pretty sure this will have to change as far as state management goes, but I wanted to make sure I could simply change the state in the parent App and have it take effect. It works on the stack screen, meaning I can call setLoggedIn(true) and it will take me to the tab navigator. But I can't go back...
const Track = () => {
return (
<TrackStack.Navigator>
<TrackStack.Screen
name='TrackListScreen'
component={TrackListScreen}
/>
<TrackStack.Screen
name='TrackDetailScreen'
component={TrackDetailScreen}
/>
</TrackStack.Navigator>
);
};
const App = () => {
const [loggedIn, setLoggedIn] = useState(false);
return (
<NavigationContainer>
{loggedIn ? //is logged in
(
<MainTab.Navigator>
<MainTab.Screen
name='TrackCreateScreen'
component={TrackCreateScreen}
initialParams={{ setLoggedIn }}
/>
<MainTab.Screen
name='AccountScreen'
component={AccountScreen}
/>
<MainTab.Screen
name='Track'
component={Track}
/>
</MainTab.Navigator>
) : (
<LoginStack.Navigator>
<LoginStack.Screen
name='SignupScreen'
component={SignupScreen}
initialParams={{ setLoggedIn }}
/>
<LoginStack.Screen
name='SigninScreen'
component={SigninScreen}
/>
</LoginStack.Navigator>
)}
</NavigationContainer>
);
};
export default App;

Custom route with List

Wondering how to use the List component from a custom route. Looks as though I'm supplying the correct props
I have a custom route of
<Route path="/facilities/:facilityId/audits" render={(props) =>
<Audits
{...props}
hasCreate={false}
hasEdit={false}
hasList={true}
hasShow={false}
resource={props.location.pathname.substring(1)}
options={{label: "a label"}}
basePath={props.location.pathname}
permissions="organisation"
/>
} />
My list component is
export const Audits = (props) =>
<List {...props}>
<Datagrid>
<TextField source="id" sortable={false} />
<TextField source="date" sortable={false} />
</Datagrid>
</List>;
However I'm getting the error of:
Uncaught TypeError: Cannot read property 'list' of undefined at Function.mapStateToProps [as mapToProps] (ListController.js:432)
...
The above error occurred in the component:
in Connect(translate(UnconnectedListController))
in Unknown (created by List)
Props in the Audits component as below:

How do you conditionally show fields in "Show" component in react-admin?

Some fields I want to only show if they have a value. I would expect to do this like so:
<Show {...props} >
<SimpleShowLayout>
{ props.record.id ? <TextField source="id" />: null }
</SimpleShowLayout>
</Show>
But that doesn't work. I can make it somewhat work by making each field a higher order component, but I wanted to do something cleaner. Here's the HOC method I have:
const exists = WrappedComponent => props => props.record[props.source] ?
<WrappedComponent {...props} />: null;
const ExistsTextField = exists(TextField);
// then in the component:
<Show {...props} >
<SimpleShowLayout>
<ExistsTextField source="id" />
</SimpleShowLayout>
</Show>
This correctly shows the value, but strips the label.
We need to update our documentation about this. In the mean time, you can find informations about how to achieve that in the upgrade guide: https://github.com/marmelab/react-admin/blob/master/UPGRADE.md#aor-dependent-input-was-removed
Here's an example:
import { ShowController, ShowView, SimpleShowLayout, TextField } from 'react-admin';
const UserShow = props => (
<ShowController {...props}>
{controllerProps =>
<ShowView {...props} {...controllerProps}>
<SimpleShowLayout>
<TextField source="username" />
{controllerProps.record && controllerProps.record.hasEmail &&
<TextField source="email" />
}
</SimpleShowLayout>
</ShowView>
}
</ShowController>
);
Maybe this way can be useful
import { FormDataConsumer } from 'react-admin'
<FormDataConsumer>
{
({ formData, ...rest}) => formData.id &&
<>
<ExistsTextField source="id" />
</>
}
</FormDataConsumer>

react-native-router-flux - trigger function on specific route load

I am trying to trigger a function whenever a specific route within a router loads. I am using react-native-router-flux 2.x and ReactNative 0.21 (Can't update to 3.x right now).
For example below I just want to trigger a function whenever screen2 is loaded. Is this possible? I tried using onPush but it didn't seem to work.
The reason I need this is because I cannot use componentDidMount, componentWillMount for the screen2 component as it will only load the first time the component is called. I need a function to trigger every time the route is selected. Thanks!
<Route name="screen1" initial={!needSignIn}>
<Router footer={TabBar} hideNavBar={true} >
<Route name="screen1" hideNavBar={true} title="Screen1" schema="tab" component={Screen1} />
<Route onPush={()=>{console.log("onPush is called!");}} name="screen2" hideNavBar={true} title="Screen2" schema="tab" component={Screen2} />
<Route name="screen3" hideNavBar={true} title="Screen2" schema="tab" component={Screen3} />
</Router>
</Route>
The only events that can fire events with react-native-router-flux are onLeft and onRight see documentation. The only to fire off functions are lifecycle functions. You said that component(Did/Will)Mount wont work, what about the others, like componentWillReceiveProps? Use componentWillMount for the first render, and componentWillReceiveProps for every other render.