How should a NavBar communicate with a Component in React Native? - reactjs

I am using 'react-native-router-flux' with my React Native app and I can't seem to figure out how my Custom Nav Bar should communicate with my component?
I have the following code.
NavigationRouter.js:
<Scene key='addDrillScreen' component={AddDrillScreen} navBar={AddDrillNavBar} />
AddDrillScreen.js:
class AddDrillScreen extends React.Component {
performSave() {
// Want to call performSave() when NavBar is clicked
}
}
AddDrillNavBar.js:
class AddDrillNavBar extends React.Component {
render() {
return (
<View style={styles.saveButton}>
<TouchableOpacity onPress={() => {
// ??? How do I trigger the performSave() on my AddDrillScreen?
}}>
<Text style={styles.saveButtonText}>Save</Text>
</TouchableOpacity>
</View>
)
}
I don't understand how the two communicate

You have a couple of options here
Make performSave static
Move performSave to a different class, one that could be shared and isn't a react component
Use the best practice for this kind of action in your flux library if you use one. For instance, in redux you would have included that code in an action creator.

Related

How to use navigation using functional component - react native

How can I use navigation using class component, the screens that I currently have on my app are functional components, and this is how I'm able to navigate from one page to another, but If try to implement this using functional comopenent it doesn't work.
export default function Activity({navigation}) {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
How Can I implemented in here :/
I tried
this.props.navigation.navigate('Home')
and I got the following error/warning
cannot update a component while rendering a different component
export default class App extends React.Component {
render() {
return (
<View style={styles.MainContainer}>
<TouchableOpacity onPress={() => navigation.navigate("Home")}>
</TouchableOpacity>
</View>
)
}
For my navigation, I had to add at the beginning of the file this importation
import { useNavigation } from '#react-navigation/native'
And in my functional component
const navigation = useNavigation()
Like this :

Make shared component with calling navigation.navigate() inside - React Native

I want to make shared component for all screen in react native. So I can share them between main components.
See my code below, everything works but the this.props.navigation.navigation.navigate('HireJob') not working.
MyCode :
export default class MyComponent extends Component {
callAndPush = () =>{
console.log('callAndPush');
this.props.navigation.navigate('HireJob')
}
render() {
return (
<TouchableHighlight style = {{backgroundColor : 'red' , height : 30}} onPress = {() => this.callAndPush()}>
<Text>Apple</Text>
</TouchableHighlight>
);
}
}
Use of Component :
render(){
return (
<View style = {styles.scrollSty}>
<MyComponent></MyComponent>
</View>
);
}
}
it works like this, bypassing navigation prop into MyComponent.
<MyComponent {...this.props} />
Every component can be imported into other components, such as navigators. They import your scenes and navigate between them by sharing props.
To make a component and use it in different places simply create one:
export default class MyComponent extends React.Component {
render() {
return (
<Text> This is a special component </Text>
);
}
}
And in your other classes use it like this:
import MyComponent from '../path/to/MyComponent';
class AnotherComponent extends React.Component {
render() {
return (
<MyComponent />
);
}
}
Starting from React 0.14, you can create these easier using stateless components:
// A functional component using an ES2015 (ES6) arrow function:
const MyComponent = (props) => {
return <Text> This is a special component </Text>
};
You can pass data using props if you like.

Differences passing Redux state through passProps with Navigator or binding state within Container

Testing React Native with Redux, and react-redux, I've found that the content of the state tree of Redux is not reflected in the display if the state is not passed through a Container.
To test this i use
react-native 0.19.0
react-redux 4.1.2
redux 3.1.7
as #alinzin explain in https://github.com/alinz/example-react-native-redux with all the tricks to setup this project. Are out there any other good solution?
The next example show a simple string as state in Redux store, and a simple action for enlarge the string.
Here is the reduce and the data as a single string in the state.
//Reducer
const reducer = (state = { data: '[][][]' }, action = {}) => {
switch (action.type) {
case ENLARGE:
return Object.assign({}, state, {
data: state.data+'[]'
})
default:
return state
}
}
The registred App is like this, nothing new. The initial route launches a Container for App1Component. This is the way for good binding state and Components (I belive)
export default class App extends Component {
render () {
return (
<Provider store={store}>
<Navigator style={{flex: 1}}
initialRoute={{
component: Container,
}}
renderScene={ (route, navigator) => {
const Component = route.component;
return (
<View style={{flex: 1, marginTop:40}}>
<Component navigator={navigator} route={route} {...route.passProps} />
</View>
);
}}
/>
</Provider>
)
}
}
The main content for both component App1Component and App2Componenet, is a simple component and just display the string, and show a 'button' to dispatch the enlarge action.
class MainContent extends Component{
render() {
return (
<View>
<Text>{this.props.data}-{this.props.data.length}</Text>
<TouchableOpacity onPress={()=>{this.props.enlarge()}} >
<Text>Click to Enlarge me!</Text>
</TouchableOpacity>
<Text> </Text>
</View>
)
}
}
There are no differences between components App1 and App2.
Just App1Component is invoked through a Container (and bind state and actions), and App2Component invoked (from App1Component) by pushing with Navigator all the same props (the same in App1Component)
Here is App1Component with a button to push next scene to App2Component and pass the same props, before binded through Container.
class App1Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{
this.props.navigator.push({
name: 'App2',
component: App2Component,
passProps: {...this.props}
})
}}>
<Text>Click to Forward to App2Component {'\n'}passing props through Navigator passProps</Text>
</TouchableOpacity>
</View>
)
}
}
If you press 'enlarge' here the string is enlarged, and you can see the action reflected on the screen. Also you can see in chrome the trace for redux logger.
Here the wrapper container for App1Component
const Container = connect(
(state) => ({
data: state.data
}),
(dispatch) => ({
enlarge: () => dispatch(enlarge())
})
)(App1Component)
And Here Component 2, with back button.
If you press 'enlarge' here the string is enlarged, sure you can see the trace on chrome, but ... the action is not reflected on the screen.
class App2Component extends Component {
render() {
return (
<View>
<MainContent {...this.props}/>
<TouchableOpacity onPress={()=>{this.props.navigator.pop()}} >
<Text>Back to App1Component{'\n'}to see the change!</Text>
</TouchableOpacity>
</View>
)
}
}
After pressing Back, you can see the string modified on screen for App1Component.
As you can see I misunderstood something fundamental, but not what is.
Have i to decorate all the mains components (Pages/Scenes) with a container?
Why is wrong to pass props (previously binded by container) through passPros in Navigator? Actions are dispatched correctly, but does not reflect on the screen.
Any help is welcome.
Thanks
It looks like passProps does not propagate updates correctly. I’m not a React Native expert so I can’t confirm it, but I would definitely recommend you to use connect() for subscribing components to Redux store rather than passing props from the top.

Need help on some concepts about ReactNative and Redux and Navigator

After several tests in this scenario, I have some questions that I can not answer my self, so I ask for help to clarify my concepts.
Provider vs props in Navigator
What is the difference and what is the best approach to setup the Navigator and pass store to different Scenes of a React Native app
export default class App extends Component {
render () {
return (
<Provider store={store}> //<-- here
<Navigator style={{flex: 1}}
initialRoute={{ component: MainContainer }} //<-- here
renderScene={ (route, navigator) => {
const Component = route.component;
return (
<View style={{flex: 1, marginTop:40}}>
<Component navigator={navigator} route={route} {...route.passProps} />
</View>
...
MainContainer is connected with Component within react-redux connect function to pass Props and Actions to props.
Is it better access to context or to props?
vs
const store = createStoreWithMiddleware(reducer, initialState); //<-- here
export default class App extends Component {
render () {
return (
<Navigator style={{flex: 1}}
initialRoute={{ component: MainComponent }}
renderScene={ (route, navigator) => {
const Component = route.component;
return (
<View style={{flex: 1, marginTop:40}}>
<Component
navigator={navigator}
route={route}
{...route.passProps}
store={store} //<-- here
/>
</View>
...
In a component Scene, (not wrapping as a smart container) how to setup a listener about changes in redux state or have i to bind component state to redux state.
Passing state (of Redux store) and actions as passProps when pushing newScene in Navigator, and in then newScene dispatch actions and executed correctly, the state is update, but... does not re-render the scene.
Do I have to bind state component to Redux state to see the changes reflected on screen?
Is there any sample about best practices in this scenario?
props vs connect in the same Scene
In the same Scene, from Top to Down components, which is the best approach to pass redux state (not talking about component state) as wrapping a component in a 'smart' container with 'connect' from react-redux, or passing the hole scenario as props.
The first solution should be used, as the provider should be the outermost component (so that everything underneath may connect properly).
You could either run a callback on componentDidReceiveProps or (what I would prefer) simply connect the component, which needs access to a store. This is exactly what redux is for. The only reason not to do this is if you would like to reuse a component with another stores content (truly representational component)
This strongly depends on the application and the depth of the components but in general, this is completely okay. You may also pass the information as props, but as your application grows bigger you may have to pass a lot of props, which may obfuscate the real intend of you components

How to switch to another module in react native?

Just implemented a login page.
After user click the login button.
How to navigate to my home page module?
The code should look like this:
login module:
class MyClient extends Component{
render() {
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button}
onPress={this.login.bind(this)}>
</TouchableHighlight>
</View>
);
}
login() {
//How to switch to home view here?
}
}
module.exports = MyClient;
Home module:
class Home extends Component{
render() {
return (
<View>
<Text>This is home page</Text>
</View>
);
}
}
module.experts = Home;
I don't want to use navigator this component cuz' I think home module & login module should not be sort of parent&child relationship.
Is there a way to switch between these two page?
You have to use the navigator. You could try to use "replace" instead of "push". With this you can achieve an instant navigation between Components.
this.props.navigator.replace({
title: 'Home', component: Home
});
And just in case you want to hide the navigation bar there is the "navigationBarHidden" property of NavigatorIOS component.
<NavigatorIOS navigationBarHidden = 'true' />

Resources