How to pass a string to screens into a BottomTabNavigator - react-native

I have a BottomTabNavigator with 4 sreens inside of it, I would like to pass a string into some of them.
How can I do that ? Thank you.
class Main extends Component {
static navigationOptions = {
title: 'Developpe Inclinné',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#e8142d',
},
};
render() {
const myPath='aRouteForFirebase'
return (
<AppContainer myPath={myPath} />
);
}
}
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session, // needs the props
Resultats // // needs the props
})
const AppContainer = createAppContainer(TabNavigator);

Here is a better implementation:
class Main extends Component {
constructor(props) {
super(props)
this.state = {
myPath: 'aRouteForFirebase',
}
this.AppContainer = createAppContainer(this.TabNavigator)
}
TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: () => <Session myPath={this.state.myPath} />},
Resultats { screen: () => < Resultats myPath={this.state.myPath} />}
})
render() {
const { AppContainer } = this
return (
<AppContainer />
)
}
}

Just for clarification:
class Main extends Component {
static navigationOptions = {
title: 'Developpe Inclinné',
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#e8142d',
},
};
render() {
const myPath='aRouteForFirebase'
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: () => <Session myPath={myPath} />},
Resultats { screen: () => < Resultats myPath={myPath} />}
}
const AppContainer = createAppContainer(TabNavigator);
return (
<AppContainer />
);
}
}
However I don't think this is good looking code, maybe you should think about integrating Redux

I can't find anything in react-navigation documentation which supports this. But I may be wrong. I can suggest one other way of doing it. Create a HOC and wrap your components with it. They all will have access to the common string.
const SomethingCommonHOC = (Component, extraProps ) => {
return class SomeComponent extends React.Component {
render() {
return <Component {...this.props} {...extraProps}/>;
}
};
};
// Use it something like this.
SomethingCommonHOC(Session);
Thanks
Edit: I understand it is difficult to explain actually. That's the reason i am not big fan of HOCs. :). I will give more try to explain you the edit required.
Create a new file:
Put this component definition in it:
const CommonHOC = (Component, extraProps) => {
return class SomeComponent extends React.Component {
render() {
return <Component {...this.props} {...extraProps} />;
}
};
};
export default CommonHOC
Then import it in your component files , in your case DeveloppeInclinne, Chrono, Session, Resultats.
In component where your need to pass common string: Let's say you are editing in session component file
import CommonHOC from the "path to CommonHOC"
export default CommonHOC(Session, {
myString: "myString"
})
Note: you can string like constant dynamic by converting 2nd param a the object and spreading inside the common component

You can do this:
const TabNavigator = createBottomTabNavigator({
DeveloppeInclinne,
Chrono,
Session: { screen: props => <Session {...props} />},
Resultats { screen: props => < Resultats {...props} />}
}
// in class Session ...
console.log(this.props.myPath)
=> aRouteForFirebase

Related

react-navigation: access stateChange event of nested navigator

I'm trying to add a state change event to a nested navigator.
Usually I would define it like this:
const TabNavigator = createMaterialTopTabNavigator({
Home: {
screen: Home,
},
Next: {
screen: NextNavigator,
},
})
but I need something like this:
const TabNavigator = createMaterialTopTabNavigator({
Home: {
screen: Home,
},
Next: {
screen: (props)=>{ return <NextNavigator {...props}/> },
},
})
where the screen object is a function.
The problem is I have no idea what signature screen as a function has, and how to pass it to the navigator
I'm getting close with something like this:
screen: (props, state)=>{ return <NextNavigator {...props} state /> },
But it's still not correct.
Does anyone know how this works?
If you don't want #JeffGuKang to answer, you can declare and use global variables and functions.
let NICKNAME = '';
function setNickName(data) {
NICKNAME = data;
}
function getNickName() {
return NICKNAME;
}
export { setNickName,getNickName }
...
//set data
import { setNickName} from './globalpath';
setNickName(data)
....
//get data
import { getNickName} from './globalpath';
getNickName()
Use Params
Use setParams, getParam for changing state in components wrapped by navigatior.
A Component (Set changing value)
const name = this.props.navigation.setParams({ name: this.state.name, age: this.state.age });
B Component (Get value)
const name = this.props.navigation.getParam('name', 'DefaultValue');
const age = this.props.navigation.getParam('age' 0);
setParams is a trigger to run getParam in other components is wrapped navigation.
Extend Navigator
You can extend the component created by Naivgator as below. link
const MyStack = createStackNavigator({ ... });
class CustomNavigator extends React.Component {
static router = MyStack.router;
state = {
a: 'b',
}
render() {
const { navigation } = this.props;
return <MyStack {...this.state, ...this.props} />;
}
}
Or it is able to use functional component instead.
const MyStack = createStackNavigator({ ... });
CustomNavigator = (props) => {
return <MyStack {...props} />
}
const TabNavigator = createMaterialTopTabNavigator({
Home: {
screen: Home,
},
Next: {
screen: (props) => { return <MyStack {...props} /> },
},
Third: CustomNavigator,
})
And do not forget import `React` to use functional component.

Passing Navigator object in renderItem

I'm struggling to make Navigator object visible in List Component.
Here the code explained: as you can see in RootDrawer, I have Concept component. It simply shows a list of items based on a id passed in param.
Each item points to another Concept with another id, but I get
undefined is not an object (evaluating 'navigation.navigate')
when I press on that <RippleButton> with onPress={() => navigation.navigate('Concept',{id:12}). The problem here I'm not passing the Navigation object correctly. How can I solve?
main Navigator drawer
const RootDrawer = DrawerNavigator(
{
Home: {
screen: StackNavigator({
Home: { screen: Home }
})
},
Search: {
screen: StackNavigator({
Cerca: { screen: Search },
Concept: { screen: Concept },
})
}
}
);
Concept component
export default class Concept extends Component {
loading = true
static navigationOptions = ({ navigation,state }) => ({
headerTitle: "",
title: `${navigation.state.params.title}` || "",
})
constructor(props) {
super(props);
}
async componentDidMount(){
}
render() {
const { params } = this.props.navigation.state;
const id = params ? params.id : null;
const { t, i18n, navigation } = this.props;
const Concept = DB.get(id)
return (
<View>
<ScrollView>
<List data={Concept.array|| []} title={"MyTile"} navigation={navigation} />
</ScrollView>
</View>
);
}
}
List Component
class List extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
const { navigation } = this.props;
}
_renderItem = (item,navigation) => (
<RippleButton
id={item.id}
onPress={() => navigation.navigate('Concept', { id: 12, otherParam: 'anything you want here'})}> //this line throws the error
<Text>{item.Term}</Text>
</RippleButton>
)
render() {
const { navigation } = this.props;
return (
<View>
<FlatList
data={this.props.data}
renderItem={({item}) => this._renderItem(item, navigation)}
/>
</View>)
}
}
Instead of passing the navigation prop, you can try using the withNavigation HOC.
Where your List Component is defined:
import { withNavigation } from 'react-navigation`
....
export default withNavigation(List)
Now the List component will have access to the navigation prop

React Navigation - Tab Navigation - Getting different screens from only one class

It is possible to change between tabs without having more then one class?
On my code I have a class that returns multiple components, and I want my TabNavigator to switch between these componentes, not between classes like they have in the React Navigation docs (https://reactnavigation.org/docs/tab-based-navigation.html).
class Monument extends Component{
render(){
const {navigate} = this.props.navigation;
const { data } = this.props.navigation.state.params;
return (
<MonumentMaker category={'Castelos'} navigate={navigate} data={data}/>
<MonumentMaker category={'Museus'} navigate={navigate} data={data}/>
<MonumentMaker category={'Igrejas'} navigate={navigate} data={data}/>
<MonumentMaker category={'Locais de Interesse'} navigate={navigate} data={data}/>
);
}
}
export default TabNavigator({
Convento: {
screen:**first component**
},
Museus: {
screen:**second component**
},
Igrejas: {
screen:**third component**
},
OutrosLocais: {
screen:**forth component**
}
})
It is possible what I want to accomplish?
Thank you for your help!
You can make your TabNavigation as follows
const myTabNavigator = TabNavigator({
Convento: {
screen: { screen: props => <Monument {...props} {...myProps} /> }
},
Museus: {
screen: { screen: props => <Monument {...props} {...myProps} /> }
},
Igrejas: {
screen: { screen: props => <Monument {...props} {...myProps} /> }
},
OutrosLocais: {
screen: { screen: props => <Monument {...props} {...myProps} /> }
}
})
Monument.js
const Monument = ({...props}, {...myProps}) => (
<View>
{...// More stuff}
</View>
)

React native navigation class function in header

I've got a problem with react native navigation and nested navigators.
Basically, the nested navigators (tab in a page) work pretty well. But when i add a button in the header with the _saveDetails function, it throw me an undefined function if i'm in the Players tab, and it works well when i'm on the Teams tab
Does anyone have an idea of what am i doing wrong? Thanks.
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerRight: <Button title="Save" onPress={() =>
params.handleSave()} />
};
};
_saveDetails() {
console.log('clicked save');
}
componentDidMount() {
this.props.navigation.setParams({ handleSave: this._saveDetails });
}
render() {
return (
<View />
);
}
}
const MainScreenNavigator = TabNavigator({
Players: { screen: HomeScreen},
Teams: { screen: HomeScreen},
});
const SimpleApp = StackNavigator({
Home: { screen: MainScreenNavigator },
Player: { screen: PlayerPage },
});
Please try this one and let me know if you fetch any other problem. Just convert your code according to below code.
static navigationOptions = {
header: (navigation, header) => ({
...header,
right: (
navigation.navigate('Settings')}>
Settings
)
})
}
Thanks
Just change your code become like this
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
// const { params = {} } = navigation.state; //delete this
return {
headerRight: <Button title="Save" onPress={() =>
navigation.state.params.handleSave()} /> // add navigation.state
};
};
.....

How to pass redux store in react native between pages?

In react native app I have 2 pages. If I upload a redux store with data on the 2 page, then return to the 1 page - how can I access the store with the uploaded data from the 2 page? So is there a way to access the store with data from all of the pages in react native?
Maybe simoke example or where to read?
Thanks
1page.js
class ScreenHome extends Component{
static navigationOptions = {
title: 'ScreenHome',
};
constructor(props){
super(props)
console.log("PROPS: ",props);
}
render() {
const { navigate } = this.props.navigation;
return (
<View>
<Button
title="Go to load data page"
onPress={() => navigate('New', { name: 'Jane' })}
/>
<Button
title="Get redux data"
onPress={() => {console.log(this.props)}}
/>
</View>
);
}
}
class ScreenRegister extends Component{
static navigationOptions = {
title: 'ScreenRegister',
};
render(){
return <Text>ScreenRegister</Text>
}
}
const MainScreenNavigator = DrawerNavigator({
Recent: {
screen: ScreenHome
},
All: {
screen: ScreenRegister
},
});
export default SimpleApp = StackNavigator({
Home: {
screen: MainScreenNavigator
},
Chat: {
screen: ScreenHome
},
New: {
screen: testScreen
}
});
const mapStateToProps = (state) => {
const {items, isFetching, done} = state.myTestData
return {testScreen:{items, isFetching, done}};
}
const mapDispatchToProps = (dispatch) => {
return {
getNewItems: () => {
dispatch(fetchData());
}
}
}
export default someTest = connect(
mapStateToProps,
mapDispatchToProps
)(SimpleApp)
2page.js
class testScreen extends Component{
static navigationOptions = {
title: 'testScreen.js',
};
_reduxStuff = () => {
this.props.getNewItems();
}
render() {
const { navigate } = this.props.navigation;
const {done, items, isFetching} = this.props.testScreen;
return (
<View>
<Text>Some new screen</Text>
<Button
title="Load Data"
onPress={() => this._reduxStuff()}
/>
</View>
);
}
}
const mapStateToProps = (state) => {
const {items, isFetching, done} = state.myTestData
return {testScreen:{items, isFetching, done}};
}
const mapDispatchToProps = (dispatch) => {
return {
getNewItems: () => {
dispatch(fetchData());
}
}
}
export default FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(testScreen)
There should be a container for each page, a store for data you want to access between pages and actions to changing this store. By using mapStateToProps you can pass this store to the container of the page. You can find good example in here.
On your first container you'll need to make your async calls to fill your store.
You can do a dispatch on your componentWillMount() and populate your store with the received data.