How to use withNavigation in react-navigation v5? - react-native

I have a nested component, and I want to use withNavigation in the nested component in react-navigation v5.

why you don't create your own withNavigation
import React from 'react';
import { useNavigation } from '#react-navigation/native'; // not sure package name
export const withNavigation = (Component: any) => {
return (props: any) => {
const navigation = useNavigation();
return <Component navigation={navigation} {...props} />;
};
};

React Navigation Version: 5.x
Sometimes you need to trigger a navigation action from places where you do not have access to the navigation prop, such as a Redux middleware. For such cases, you can dispatch navigation actions from the navigation container.
If you're looking for a way to navigate from inside a component without needing to pass the navigation prop down. Do not use this method when you have access to a navigation prop or useNavigation since it will behave differently, and many helper methods specific to screens won't be available.
You can get access to the root navigation object through a ref and pass it to the RootNavigation which we will later use to navigate.
// App.js
import { NavigationContainer } from '#react-navigation/native';
import { navigationRef } from './RootNavigation';
export default function App() {
return (
<NavigationContainer ref={navigationRef}>{/* ... */}</NavigationContainer>
);
}
In the next step, we define RootNavigation, which is a simple module with functions that dispatch user-defined navigation actions.
// RootNavigation.js
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
// add other navigation functions that you need and export them
Then, in any of your javascript modules, just import the RootNavigation and call functions that you exported from it. You may use this approach outside of your React components and, in fact, it works just as well when used from within them.
// any js module
import * as RootNavigation from './path/to/RootNavigation.js';
// ...
RootNavigation.navigate('ChatScreen', { userName: 'Lucy' });
Apart from navigate, you can add other navigation actions:
import { StackActions } from '#react-navigation/native';
export function push(...args) {
navigationRef.current?.dispatch(StackActions.push(...args));
}
https://reactnavigation.org/docs/navigating-without-navigation-prop/

Related

How can I pass params through react-navigation module without navigate to other page?

I am using react-navigation module to implement the bottom tab bar, and now I want to pass the parameters to page B during the operation in page A without page jumping, is there any way to achieve this?
I read the official documentation of react-navigation, and it seems that only the navigation.navigation method can pass parameters across pages, but this will cause page jumps
You can use the AsyncStorage package. Save the data you will use on PageB with a key on PageA. Then get saved data on the PageB.
import React, { useEffect } from 'react';
import { Button } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
export default PageA = ({ navigation }) => {
useEffect(() => {
AsyncStorage.setItem("PageParams", "something")
}, [])
return (
<Button title='Navigate' onPress={() => navigation.navigate("PageB")} />
);
};
import { View } from 'react-native';
import React, { useEffect } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
export default PageB = () => {
useEffect(async () => {
const params = await AsyncStorage.getItem("PageParams")
console.log(params) // output: something
})
return (
<View />
);
};

React Native navigation ref always null

I have the following:
import {navigationRef} from "./wherever"
<NavigationContainer ref={navigationRef}>
In the navigation file I import, I have this
import React from 'react';
const navigationRef = React.createRef();
const navigate = (name, params) => {
console.log(navigationRef)
navigationRef.current?.navigate(name, params);
}
export default {
navigate
}
But when in my code I try to call the following:
import navigation from './wherever';
navigation.navigate('wherever')
the console log always shows
{"current": null}
and so the navigation never kicks in. Can anyone help?
the rubber duck technique in action, I answered my own question in the act of describing it to you all!
I was simply missing an export.
export default {
navigate,
navigationRef
}
And so I changed my import like so:
import navigation from "./wherever"
<NavigationContainer ref={navigation.navigationRef}>

execute hooks inside a function in react native

Can I use hooks inside a function? For example I have implemented the following code:
import React, { useState, useEffect, Component} from 'react';
export default class App extends Component {
checkdata_db(){
const [booblenavalue,setboolenavalue]=useState(false);
useEffect(() => {
setboolenavalue(true)
}, [])
console.log(booblenavalue);
}
render(){
}
}
This code doesn't work. It throws the following error:
Invalid hooks call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app"
How can i run hooks inside checkdata_db method?
Hey #Elly as #yousoumar said , you cant use hooks in classes , it can be only done with functional comp:
You can convert it to like this :
Also you cant use useEffect,useState inside any conditional statements like if,else etc.
So you need to add useEffect outside any functions etc
import React, { useState, useEffect, Component} from 'react';
const App = () => {
const [booblenavalue,setboolenavalue]=useState(false);
useEffect(() => {
setboolenavalue(true)
}, [])
const checkdata_db = () => {
console.log(booblenavalue);
}
return <View />
}
Hope it helps feel free for doubts

How to use the same socket on different pages in react native

I am using Socket.io for chatting feature in my react-native project. My project is using react native navigation.
But I have trouble things passing Socket.io socket to certain screens. I want to share the socket with the navigation( like a prop I think I'm not sure ).
Currently I'm using Socket.io socketes on each certain screens individually. But this way has some troubles.
The main trouble is that when someone sends me a message I need to know which page I'm on while the app is running.
Does someone have any suggestions on how to do it?
My target is to share the same socket with three pages.
I googled, but couldn't find any suitable results.
- AppNavigation.js
import React from 'react';
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
// Chat.
import ChatScreen from '../screens/Chat/ChatScreen';
import VideoChatScreen from '../screens/Chat/VideoChatScreen;
const Stack = createStackNavigator();
function AppNavigator() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Chat" component={ChatScreen} options={{ headerShown: false, gestureEnabled: false }}/>
<Stack.Screen name="VideoChat" component={VideoChatScreen} options={{ headerShown: false, gestureEnabled: false }}/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default AppNavigator;
- ChatScreen.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
import SocketIOClient from 'socket.io-client'
class ChatScreen extends Component {
constructor() {
super()
this.state = {}
this.socketClient = null;
}
componentDidMount() {
this.socketClient = SocketIOClient(url);
this.socketClient.onAny((event, params) => {
this.onResponseOnSocket(event, params);
});
}
...
- VideoChatScreen.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
class VideoChatScreen extends Component {
constructor() {
super()
this.state = {}
this.socketClient = null;
}
componentDidMount() {
this.socketClient = SocketIOClient(url);
this.socketClient.onAny((event, params) => {
this.onResponseOnSocket(event, params);
});
}
...
You can use a state management tool of your choice to manage a global (App-)State within your app. With functional components I like ContextProvider which is part of RN Core and is still o.k. for class components as long as you have only a few Provider. But many people use Redux or you can use facebooks Recoil which is also an interesting alternative.
https://reactjs.org/docs/context.html
https://redux.js.org/introduction/getting-started
https://recoiljs.org/
I think my library will be perfect for your case.
It is the state managment tool dedicated to chat applications: https://github.com/chatscope/use-chat
Your application should be wrapped with ChatProvider component, and you need to create your own service/adapter that will be responsible for websocket connection.
Sending messages, message list, conversations etc. are available in all child components with one hook.

Context API w/ React Navigation (React Native)

I'm trying to wrap my mind around using Context in my React Native app that uses React Navigation. I think I am way off on this one. I am simply trying to pass the name of a book to my entire app through the navigation stacks.
App.js
const BookContext = React.createContext();
class BookProvider extends Component {
state = {
name: 'book name'
}
render() {
return (
<BookContext.Provider value={{
name: this.state.name
}}>
{this.props.children}
</BookContext.Provider>
)
}
}
export default function App() {
return (
<BookProvider>
<BookContext.Consumer>
{({ name }) => (<Routes name={name} />)} //my react navigation stacks component
</BookContext.Consumer>
</BookProvider>
);
}
and in Book.js (a component in the navigation stack)
componentDidMount() {
console.log(this.context)
}
returns an empty object {}
Any help is appreciated!
To save you some Googling, this is the correct approach: https://github.com/react-navigation/react-navigation/issues/935#issuecomment-359675855
Another way, if you're using a relatively new version of React, and your component in question at that route is a functional component, is to use the useContext React hook.
e.g.
import React, { useContext } from 'react'
import { BookContext } from '/path/to/BookContext'
function BookConsumerComponent() {
const { name } = useContext(BookContext);
console.log(name);
}