In React navigation v4 we pass the null screen like this:
`Screen: {
screen: () => null,
navigationOptions: {
tabBarIcon: <AddButton />
}
},`
But How to I can do it in react navigation 5?
I choose this path for the screens I want to hide. May be help you. I manage isLogin with Mobx.
{MenuStore.isLogin ? <></>
: <Drawer.Screen
name="Login"
component={LoginStackScreen}
/>
You can pass <NavigatorName.Screen name="ScreenName">{() => null}</NavigatorName.Screen> to pass null as a screen.
You can use event listener on the tab bar
<Tab.Screen
name="Plus"
component={Add}
listeners={{
tabPress: (e) => {
e.preventDefault(); // — > the main part
},
}}
/>
Where Add is
const Add = () => { return null; };
I am following these 2 samples:
Webchat with react
Programmatic post activity
My bot is working ok. I can send and process activities via directline. My test helpButton logs ok, but there is no actual 'help' message sent when I click the button like in the sample.
var mainBotConnection;
const { createStore, ReactWebChat } = window.WebChat;
const { createProvider } = window.ReactRedux;
const Provider = createProvider('webchat');
const Store = createStore();
// get a token
const RequestToken = async (user) => {
...
};
(async function () {
RequestToken(agent)
.then(token => {
//init main chat bot
mainBotConnection = window.WebChat.createDirectLine({token: token});
...
//grab mainbot placeholder and put it on screen
window.ReactDOM.render(
<Provider store={Store}>
<ReactWebChat
directLine={mainBotConnection}
storeKey='webchat'
userID={user.id}
username={user.name}
styleOptions={mainBotStyleOptions}
/>
</Provider>,
document.getElementById('webchat'));
// this message does not appear
Store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: { text: 'StartUp hello!' }
});
});
// test button
document.querySelector('#helpButton').addEventListener('click', () => {
// this is successfully logged
console.log(`help button clicked`);
// 'help' text does not appear in bot
Store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: { text: 'help' }
});
// this is also successfully logged
console.log(Store);
});
document.querySelector('#webchat').focus();
})().catch(err => console.error(err));
You need to add store={Store} to your ReactWebChat component:
[...]
<Provider store={Store}>
<ReactWebChat
directLine={mainBotConnection}
storeKey='webchat'
userID={user.id}
username={user.name}
styleOptions={mainBotStyleOptions}
store={Store} // ADD THIS PART
/>
</Provider>,
[...]
That being said, without the rest of your code, I wasn't able to test this exactly. Instead, I started up the React with Redux Sample. If I removed store={Store}, it didn't work, but if I left it in there, it worked just fine and sent both the welcome and help messages. You may also need: <Provider store={ store } key='webchat'>, but like I said, I wasn't able to test your exact code.
I'd like to have a TabNavigator embedded in a StackNavigator with a button in the Header used to navigate in the main Stack.
Here is a snack of my issue: https://snack.expo.io/#guigui64/tabs-in-stack
The propblem is when I create the TabNavigator:
const TabNavigator = createMaterialTopTabNavigator(
{
ScreenA,
ScreenB,
},
{
navigationOptions: {
headerTitle: 'Title when in tab',
headerRight: (
<Button
onPress={() => this.props.navigation.navigate('C')} // here is the issue !
title="ScreenC"
/>
),
},
}
);
I also tried creating a Component with static navigationOptions and have render() return a TabNavigator. In this case, the header appears fine but not the tabs.
Thanks in advance !
How to change the direction of the animation in StackNavigator?
Current Behavior
When user goes to another screen, the screen flies from bottom to top.
Expected Behavior
When user goes to another screen, the screen flies from right to left. (Like Facebook or Instagram!)
StackNavigator Code
export default StackNavigator ({
Main: {
screen: MainScreen,
},
...
}, {
navigationOptions: ({navigation, screenProps}) => ({
tabBarOnPress: blahblaj
}),
lazy: true
// I guess we can do something here
});
If we can set the animation time, it will be even better! Currently it looks like the screen flies from middle of the screen to top. I want natural animation like Facebook or Instagram :)
Thanks in advance,
For react navigation > 5.0:
import {
CardStyleInterpolators,
createStackNavigator,
} from '#react-navigation/stack';
const Stack = createStackNavigator();
export default () => (
<Stack.Navigator
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS
}}
>
<Stack.Screen name="Screen 1" component={ScreenComponent1} />
<Stack.Screen name="Screen 2" component={ScreenComponent2} />
</Stack.Navigator>
);
You may also want to use headerStyleInterpolator: HeaderStyleInterpolators.forUIKit
More info here: https://reactnavigation.org/docs/stack-navigator/#pre-made-configs
For react navigation < 5.0
On iOS it's standard behavior. Android requires a little bit of configuration. There are two options you can use to set screen transitions: mode and transitionConfig. In this case transitionConfig will work:
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStack/CardStackStyleInterpolator';
// this path can be different depending on react-navigation version, this one is for #1.0.0-beta.15
export default StackNavigator ({
Main: {
screen: MainScreen,
},
...
}, {
transitionConfig: () => ({
screenInterpolator: CardStackStyleInterpolator.forHorizontal,
}),
})
We use CardStackStyleInterpolator from react-navigation source, but you can provide custom transition if you want, here is how to make one or here or this article.
mode is more for default behavior:
export default StackNavigator ({
Main: {
screen: MainScreen,
},
...
}, {
mode: 'card',
navigationOptions: ({navigation, screenProps}) => ({
tabBarOnPress: blahblaj
}),
lazy: true
});
mode can have only two values:
card - Use the standard iOS (right to left) and Android (bottom to
top) screen transitions. This is the default.
modal - Make the screens slide in from the bottom which is a common
iOS pattern. Only works on iOS, has no effect on Android.
For react navigation >= 5.0:
import {
CardStyleInterpolators,
createStackNavigator,
} from '#react-navigation/stack';
const Stack = createStackNavigator();
export default () => (
<Stack.Navigator
screenOptions={{
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS
}}
>
<Stack.Screen name="Screen 1" component={ScreenComponent1} />
<Stack.Screen name="Screen 2" component={ScreenComponent2} />
</Stack.Navigator>
);
You may also want to use headerStyleInterpolator: HeaderStyleInterpolators.forUIKit
More info here: https://reactnavigation.org/docs/stack-navigator/#pre-made-configs
Updated answer:
import ReactNavigation from "react-navigation";
createStackNavigator({...},{
transitionConfig: () =>
ReactNavigation.StackViewTransitionConfigs.SlideFromRightIOS
})
Here,I just post my answer so that you can change the direction of the animation! That's all! The answer you have accepted is just default!
import CardStackStyleInterpolator from 'react-navigation/src/views/CardStackStyleInterpolator';
export default StackNavigator ({
Main: {
screen: MainScreen,
},
...
}, {
transitionConfig: () => ({
screenInterpolator: CardStackStyleInterpolator.forHorizontal,
}),
});
In this way, the screen transitions will become right to left on both two platforms!
What you need to pay more attention to is you can set any screen transitions whatever you want by using transitionConfig props!
The solution is very simple. In React navigation 4.x you can do like this
import { createAppContainer } from 'react-navigation'
import { createStackNavigator, StackViewTransitionConfigs } from 'react-navigation-stack';
const Navigation = createStackNavigator({
screenA: ComponentA,
screenB: ComponentB,
}, {
mode: 'card',
transitionConfig: () => StackViewTransitionConfigs.SlideFromRightIOS,
}
export const AppNavigation = createAppContainer(Navigation)
Note: You can achieve like this transition in previous react navigation versions also, but you have to change the import
animation​
How the screen should animate when pushed or popped.
Supported values:
default: use the platform default animation
fade: fade screen in or out
fade_from_bottom: fade the new screen from bottom
flip: flip the screen, requires stackPresentation: "modal" (iOS only)
simple_push: default animation, but without shadow and native header transition (iOS only, uses default animation on Android)
slide_from_bottom: slide in the new screen from bottom
slide_from_right: slide in the new screen from right (Android only, uses default animation on iOS)
slide_from_left: slide in the new screen from left (Android only, uses default animation on iOS)
none: don't animate the screen
Only supported on Android and iOS.
I want to show progress/activityindicator whenever I make an api call from my app, But I can't find the correct solution for this. I can show the activityindicator but I can't hide it from view. Here is my code:
StatusModal.js
constructor(props) {
super(props)
// set state with passed in props
this.state = {
message: props.error,
hide: props.hide,
animating: props.animating
}
}
render() {
if(this.state.animating){
return(
<ActivityIndicator
animating={true}
size="small"
/>
)
}else{
return(
<View>
</View>
)
}
}
and here is how I change the animating state
//show activity
Actions.statusModal({animating: true})
//hide activity
Actions.statusModal({animating: false})
and here is my scene structure:
<Scene key="modal" component={Modal} >
<Scene key="root">
<Scene key='login' component={Login} title='Login Page' hideNavBar={true} />
</Scene>
<Scene key="statusModal" component={StatusModal} />
</Scene>
How can I hide the activity indicator from actions?
It's pretty common thing for applications to handle loading.
The simplest way to handle it is create a separate reducer for this.
E.g.:
function appStateReducer(state = { loading: false }, action) {
switch(action.type) {
case "SET_LOADING":
return { loading: action.payload };
default:
return { loading: false };
}
}
...
const rootReducer = combineReducer(
...otherReducers,
app: appStateReducer
);
...
Later you can use it in your components.
...
const mapStateToProps = (state) => ({
loading: state.app.loading,
});
#connect(mapStateToProps)
class MyScene extends Component {
...
render() {
const { loading } = this.props;
if (loading) {
return (
);
}
return ;
}
Dispatch action SET_LOADING in the start of query with true and dispatch SET_LOADING with false in the end or in case of error.
But one single state for handling loading isn't enough for big application. For example: you need to handle parallel queries to API and to show loader for every single query. Then you'll need such fields in other reducers.
By the way, you'll definitely meet the issue with async flow. I would recommend such middlewares as redux-thunk, redux-saga and redux-observable.
My favourite one is redux-saga. It's a very powerful way to control your async flow and all other side effects in your application.
I hope it helps.