Fluent UI React commandbar usestate not possible - reactjs

I am a newbee on Fluent UI React components. I am trying to implement React Router on the commandbar control from fluent UI react found here it is CommandBar with overflowing menu items. If I want to navigate to a different page with the menu items I use the history.push("/myLink") as explained here. But in order to get that working I would need to have access to useState in the functional component. the code looks like this:
export const CommandBarBasicExample: React.FunctionComponent = () => {
const [refreshPage, setRefreshPage] = useState(false);
return (
<div>
<CommandBar
items={_items}
overflowItems={_overflowItems}
overflowButtonProps={overflowProps}
farItems={_farItems}
ariaLabel="Use left and right arrow keys to navigate between commands"
/>
</div>
);
};
const _items: ICommandBarItemProps[] = [
{
key: 'newItem',
text: 'New',
cacheKey: 'myCacheKey', // changing this key will invalidate this item's cache
iconProps: { iconName: 'Add' },
subMenuProps: {
items: [
{ //first item in the menu
key: "AddProperty",
text: "Properties",
iconProps: { iconName: "Add" },
["data-automation-id"]: "newProperty", // optional
onClick: ()=>{handleclick()
setRefreshPage(true);
};
{
key: 'calendarEvent',
text: 'Calendar event',
iconProps: { iconName: 'Calendar' },
},
],
},
},
The Problem I have is that if I use setRefreshPage(true) VS code complains that the state variable is not recognized. if I put the useState somewhere else React complaints of a illegal use of useState. How can I get useState to be usable in the const _items object??
any help would be greatly appreciated.

Here's what's working for me with the same command bar component.
You have to make sure your router is setup as HashRouter and the path properties of your <Route/> s are setup like /#properties through the href property of the button - and not through onClick.
We have the routes file describing the routes:
/* routes.js */
export const Routes = {
Properties: 'properties'
}
We have this file, describing the contents of the command bar.
/* commandBarItems.js */
import Routes from './routes'
// IMPORTANT - CHECK OUT THE HREF PROP
const PropertiesButton = { key: Routes.Properties, name: 'Properties', href: `#${Routes.Properties}` };
export const CommandBarItems = { menu: [PropertiesButton] }
We have the app.js where you setup the hash router and the command bar component.
/* app.js */
import React, { Component } from 'react';
import { HashRouter as Router, Route } from "react-router-dom";
import { Fabric, initializeIcons, CommandBar } from 'office-ui-fabric-react';
import { PropertiesComponent } from './whichever-file-or-module';
import Routes from './routes';
import CommandBarItems from './commandBarItems';
class App extends Component {
constructor() {
super();
initializeIcons();
...
}
render() {
return (
<div>
<Fabric>
<Router>
<React.Fragment>
<CommandBar items={CommandBarItems.menu} farItems={CommandBarItems.farItems}/>
<Route path={`/${Routes.Properties}`} component={PropertiesComponent} />
</React.Fragment>
</Router>
</Fabric>
</div>
);
}
}

Related

this.props.history showing undefine in console in React JS

In my react app I want to send state to the next path through the history.location.state and history.location.pathname
In my case, it has to push successfully and also showing in history but when I console.log(this.props.history) in the child page showing undefined.
MyComponent Code
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
class MyComponent extends Component {
state = {
cart: {
1:{
icon: "URL"
id: 1
quantity: 1
title: "item1"
}
2:{
icon: "URL"
id: 2
quantity: 1
title: "item2"
}
}
}
submitHandler = (event) => {
event.preventDefault();
let data = {};
for (let key in this.state.cart) {
data[key] = this.state.cart[key]
}
console.log("data=",data);
this.props.history.push({
pathname: "/result",
state: { data: data }
});
}
render(){
return(
<div >
<button onClick={this.submitHandler}>CONTINUE</button>
</div>
)
}
}
export default withRouter(MyComponent);
Result Component
import React, { Component } from 'react';
class Result extends Component {
render() {
console.log("ss=",this.props.history);
return(<div>Result</div>)
}
export default Result;
In Console
Route
<Route path="/result" component={Result} />
As shown in the above img in history->location->state is push fine.
But when I console log to this.props showing undefined.
Also I already use withRouter hoc of react-router-dom in export
Suggest me a solution to this?
May be you are called wrong path. its working and the state variable available on this.props.location not a this.props.history;
Codesanbox example

Cannot Deep Link Into Nested React Native Navigators

I'm experiencing an issue with React Navigation 2.18.3. I cannot deep link to a route that belongs to a navigator that is nested. I have a top-level tab navigator, MainTabNavigator which has two routes, Home and Menu:
import React, { PureComponent } from 'react';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Explore from '../Home/Home';
import Menu from '../Menu/Menu';
import { TabBarContainer as TabBar } from './TabBar';
class MainTabNavigator extends PureComponent {
getRoutes() {
return {
Explore: { screen: Explore },
Menu: { screen: Menu, path: 'menu' }
};
}
getOptions() {
return {
tabBarComponent: TabBar,
tabBarPosition: 'bottom',
swipeEnabled: false
};
}
render() {
const TabNavigator = createMaterialTopTabNavigator(
this.getRoutes(),
this.getOptions()
);
return (
<TabNavigator uriPrefix="myapp://" />
);
}
}
export default MainTabNavigator;
Menu itself is a stack navigator:
import React, { Component } from 'react';
import { createStackNavigator } from 'react-navigation';
import MenuPage from './MenuPage';
import Products from '../Products/Products';
import onNavigationStateChange from '../../util/onNavigationStateChange';
import Settings from './Settings/Settings';
class Menu extends Component {
getRoutes() {
return {
MenuPage: { screen: MenuPage, path: 'page' },
Products: { screen: Products, path: 'products' },
Settings: { screen: Settings }
};
}
getOptions() {
return {
initialRouteName: 'MenuPage',
headerMode: 'none',
cardStyle: { backgroundColor: '#fff' }
};
}
render() {
const Navigation = createStackNavigator(this.getRoutes(), this.getOptions());
const screenProps = { rootNavigation: this.props.navigation };
return (
<Navigation
uriPrefix="myapp://menu"
screenProps={screenProps}
onNavigationStateChange={onNavigationStateChange}
/>
);
}
}
export default Menu;
When I go to safari and navigate to myapp://menu/products, the Menu navigator navigates correctly, but the MainTabNavigator stays stuck on Home. To the user, it looks like no navigation took place. If the user then navigates to the Menu, they will find that the Menu is already navigated to the Products page.
How can I get MainTabNavigator to navigate correctly when responding to a deep link?
To anyone experiencing a similar problem:
The issue was that we were explicitly rendering our Navigators. As it says in the "Common Mistakes" section of the docs:
Most apps should only ever render one navigator inside of a React component, and this is usually somewhere near the root component of your app. This is a little bit counter-intuitive at first but it's important for the architecture of React Navigation.
Apparently, failing to do so prevents you from being able to deep link all the way through your navigators ¯\_(ツ)_/¯

React Navigation Component on redirect loses data when refreshes

I am using React 16.4.1 and React-Router-Dom 4.3.1. I have built a side bar react component using a web component that you pass the data into the web component and this renders the component.
Here is the side bar component.
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { Redirect } from 'react-router-dom';
class Sidebar extends React.Component {
constructor(props, context) {
super(props, context);
this.mySideBarRef = React.createRef();
this.menuClick = this.menuClick.bind(this);
this.state = {
redirect: false,
redirectUrl: '/',
menuData: [
{
groupName: 'Group 1',
icon: 'Home',
children: [
{
title: 'Home',
icon: 'favorite',
url: '/',
},
{
title: 'Grp 1 Item 2',
children: [
{
title: 'Roles',
icon: 'Person',
url: '/roles',
},
{
title: 'About',
icon: 'gesture',
url: '/about',
},
{
title: 'Google',
icon: 'world',
url: 'http://www.google.co.uk',
},
],
},
],
},
{
groupName: 'Group 2',
icon: 'search',
children: [
{
title: 'Grp 2 Item 1',
icon: 'microsoft',
children: [
{
title: 'Grp 2 Item 1.1 Bing',
icon: '',
url: 'http://www.google.co.uk',
},
{
title: 'Grp 2 Item 1.2 Bing',
icon: '',
url: 'http://www.bing.com',
},
],
},
],
},
],
};
}
componentDidMount() {
let sideMenuContainer = this.mySideBarRef.current;
sideMenuContainer.sideMenuData = this.state.menuData;
sideMenuContainer.overrideCustomUrlEvent = true;
window.addEventListener('customUrlEvent', this.menuClick)
}
menuClick(e) {
console.log(e);
this.setState({
redirect: true,
redirectUrl: e.url
});
}
componentWillUnmount() {
this.mySideBarRef.current.removeEventListener('customUrlEvent', this.menuClick);
}
render() {
if(this.state.redirect) {
this.state.redirect = false;
return <Redirect to={this.state.redirectUrl} />;
}
if(this.state.menuData !== null) {
return(
<side-bar-component
ref={this.mySideBarRef}
collapsable>
</side-bar-component>
);
}
}
}
export default Sidebar;
When the side-bar component loads it renders the data correctly, as soon as you click on one of the links it does redirect the page but the data does not load, because the componentDidMount does not get triggered. Here is the app.js
// This component handles the App template used on every page.
import React from 'react';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import Header from './common/header';
import {connect} from 'react-redux';
import HomePage from './home/home-page';
import RolesPage from './role/roles-page';
import AboutPage from './about/about-page';
import { ManageRolePage } from "./role/manage-role-page";
import Sidebar from "./common/sidebar"; //eslint-disable-line import/no-named-as-default
class App extends React.Component {
render() {
return (
<div>
<Header
loading={this.props.loading}
/>
<div>
<div className="demo-sidebar-container">
<Sidebar />
</div>
<div className="demo-content">
<Route exact path="/" component={HomePage}/>
<Route path="/roles" component={RolesPage}/>
<Route path="/role/:id" component={ManageRolePage}/>
<Route path="/role" component={ManageRolePage} exact />
<Route path="/about" component={AboutPage}/>
</div>
</div>
</div>
);
}
}
App.propTypes = {
loading: PropTypes.bool.isRequired,
match: PropTypes.object.isRequired
};
function mapStateToProps(state, ownProps) {
return {
loading: state.ajaxCallsInProgress > 0
};
}
export default connect(mapStateToProps)(App);
Being new to react I think I am missing a fundamental step, what I am trying to achieve is for the redirect to happen and also have the choice depending on business logic to either reload the data into the side menu or to retain the data as the clicked item will be expanded and would like to retain the side menu data. My example above has a hard-coded data-set but eventually I would have a service that would be parameterised. Any guidance or examples on what I am trying to achieve would be grateful.
**
After reading Adams comments I have made the following changes: I
lifted all the code into sidebar-container.js and now my sidebar.js
looks like this;
**
import React from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { Redirect } from 'react-router-dom';
const Sidebar = React.forwardRef((props, ref) => (
<dijits-ui-dds-sidebar
ref={ref}
collapsable>
</dijits-ui-dds-sidebar>
));
export default Sidebar;
**
My sidebar-container.js file now consists of all the logic for
controlling the side bar:
**
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as sideMenuActions from '../../actions/side-bar-actions';
import Sidebar from "./sidebar";
import sideMenu from "../../reducers/side-menu-reducer";
import {Redirect} from "react-router-dom";
class SidebarContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.mySideBarRef = React.createRef();
this.menuClick = this.menuClick.bind(this)
this.state = {
redirect: false,
redirectUrl: '/',
sideMenu: Object.assign({}, this.props.sideMenu),
};
}
componentDidMount() {
let sideMenuContainer = this.mySideBarRef.current;
if(this.state.sideMenu.menuData !== undefined) {
sideMenuContainer.sideMenuData = this.state.sideMenu.menuData;
}
sideMenuContainer.overrideCustomUrlEvent = true;
window.addEventListener('customUrlEvent', this.menuClick);
}
componentWillReceiveProps(nextProps) {
if (nextProps.sideMenu !== this.state.sideMenu) {
let sideMenuContainer = this.mySideBarRef.current;
if(nextProps.sideMenu.menuData !== undefined) {
sideMenuContainer.sideMenuData = nextProps.sideMenu.menuData;
}
}
}
componentWillUnmount() {
this.mySideBarRef.current.addEventListener('customUrlEvent', this.menuClick);
}
menuClick(e) {
console.log(e);
this.setState({
redirect: true,
redirectUrl: e.url
});
}
render() {
if(this.state.redirect) {
this.setState({ redirect: false} );
return <Redirect to={this.state.redirectUrl} />;
}
return (
<div>
<Sidebar sideMenu={this.props.sideMenu} ref={this.mySideBarRef}/>
</div>
);
}
}
SidebarContainer.propTypes = {
sideMenu: PropTypes.object.isRequired
};
function mapStateToProps(state, ownProps) {
debugger;
return {
sideMenu: state.sideMenu,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(sideMenuActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps) (SidebarContainer);
**
And the sidebar containers sit's in my app.js.
**
import React from 'react';
import PropTypes from 'prop-types';
import { Route } from 'react-router-dom';
import Header from './common/header';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import HomePage from './home/home-page';
import RolesPage from './role/roles-page';
import AboutPage from './about/about-page';
import { ManageRolePage } from "./role/manage-role-page";
import SidebarContainer from "./common/sidebar-container"; //eslint-disable-line import/no-named-as-default
class App extends React.Component {
render() {
return (
<div>
<Header
loading={this.props.loading}
/>
<div>
<div className="sidebar-container">
<SidebarContainer sideMenu={this.props.sideMenu} />
</div>
<div className="content">
<Route exact path="/" component={HomePage}/>
<Route path="/roles" component={RolesPage}/>
<Route path="/role/:id" component={ManageRolePage}/>
<Route path="/role" component={ManageRolePage} exact />
<Route path="/about" component={AboutPage}/>
</div>
</div>
</div>
);
}
}
App.propTypes = {
loading: PropTypes.bool.isRequired,
sideMenu: PropTypes.object.isRequired,
match: PropTypes.object.isRequired
};
function mapStateToProps(state, ownProps) {
debugger;
return {
loading: state.ajaxCallsInProgress > 0,
sideMenu: state.sideMenu,
};
}
export default connect(mapStateToProps)(App);
**
But I am still getting the same issue of when I click on a items on
the side menu bar to route me to a different route the bar loses the
data. I know the reason why, but trying to find a solution to this.
The menuClick(e) function in the container set the redirect property
and the redirectUrl state values which refreshes the state and forces
the parent container to reload, I also in the render need to set the
state of the redirect back to false. Which is causing the parent to
refresh being the container and then forcing the sidebar to refresh. I
feel I am missing something or misunderstanding something within react
way of doing things. Also I have an action that executes to bring the
initial load of the side bar and it looks like the componentDidMount
was not setting the propType for the child component, so I added the
componentWillReceiveProps lifecycle method which picked up propType
changes. So does this mean that I do not need to have the following
line in the componentDidMount method?
**
if(this.state.sideMenu.menuData !== undefined) {
sideMenuContainer.sideMenuData = this.state.sideMenu.menuData;
}
**
Apologise for my slow response, but I look forward for your
assistance. Once again thank you community for your support.
**
Also include my routes.js in case this might be needed to help troubleshoot this issue.
import React from 'react';
import { Route, IndexRoute, Switch } from 'react-router-dom';
// import { Route, IndexRoute } from 'react-router';
import App from './components/app';
import HomePage from './components/home/home-page';
import AboutPage from './components/about/about-page';
import RolesPage from './components/role/roles-page';
import ManageRolePage from './components/role/manage-role-page'; //eslint-disable-line import/no-named-as-default
export default (
<Switch>
<Route path="/" components={App}>
<IndexRoute component={HomePage} />
<Route path="roles" component={RolesPage}/>
<Route path="role" component={ManageRolePage}/>
<Route path="role/:id" component={ManageRolePage}/>
<Route path="about" component={AboutPage}/>
</Route>
</Switch>
);
After a little more playing I changed the menuClick event to use a private variable rather then state variables for redirectUrl or for redirect flag.
menuClick(e) {
console.log(e);
this.redirectUrl = e.url;
this.redirect = true;
}
Which means that state is not being updated but I can retain the menu expand but page does not redirect because I am not hitting the render function event.
Components will re-render whenever their state or props change, meaning their render method will run again, and their relevant lifecycle methods.
The thing I notice the most about your code is that you are using the Route, but you are not using a Switch or BrowserRouter. This may be related. I can't tell for sure, but because your <SideBar> component is upstream from the Routes, it will simply not re-render or update unless its state or props change.
I would think your sidebar would just not update and the data may load initially but would become stale.
But never fear, allow me to link you an article that I think will bring you to the next level: https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf (note to future individuals: if that URL breaks in the future, let me know)
I think you will figure it out after reading that, but it will detail BrowserRouter, Switch, and Route. I think you need to change your code to use all three of those.
Remember that the Sidebar (and all of its children) will only update if it's state or props change.
You could do something like this:
class App extends Component {
constructor(props) {
super(props)
this.state = {
data: {},
}
}
render() {
return (
<div>
<Sidebar data={this.state.data} />
<AnotherComponent onEventOccurred={newData => this.setState({ data: newData })} />
</div>
)
}
}
In React, we call it lifting state, so the parent of your Sidebar would be the component that controls the state that the sidebar relies on. Inside the Sidebar, you could refer to that state as this.props.data (or if it was a stateless functional component, as props.data). The sidebar would re-render itself every time that prop changed.
The second part of that is shown by:
<AnotherComponent onEventOccurred={newData => this.setState({ data: newData })} />
That component has a prop called onEventOccurred which could be called from inside that component as this.props.onEventOccurred(newData) or if functional non-class component as props.onEventOccurred(). It's literally just a callback, so you call it and it fires this.setState() in its parent. It is an extremely powerful pattern because it allows the parent to control what it will do for that event because the action is defined in the parent. The child simply triggers the callback.
I was initially hesitant to post an answer, but I now feel like you might get a lot out of this. Let me know if anything specific is still unclear. I want you to read the whole Medium article I linked first. The pattern shown in it is very common and idiomatic.
I just noticed you have Redux installed. This is a definite increase in complexity overall, but it is good for cross-cutting concerns. Sometimes we call it sideways data loading. Normally, data flows unidirectionally in React, meaning always from parent to child, upstream to downstream.
With Redux, you would call an action creator from any of your components and your Sidebar would be listening to changes on the state Object. Redux is used when you want pieces of state to be shared across multiple components not directly connected to eachother.
With Redux, connected components are listening for changes on the 'basically' global state tree. When the state changes, components that are subscribed will update.
For example in your Sidebar, you could have this:
function mapStateToProps(state, ownProps) {
return {
loading: state.ajaxCallsInProgress > 0,
data: state.sidebar,
};
}
and it would update its this.props.data every time state.sidebar changed. I'm trying to keep this as minimal as possible because I may fantastically confuse you with extra info, but that is the most important part. Components using connect() are subscribed to changes on the global state tree.
Connect is a higher order component that wraps around the component using it, so when the app's state changes, it causes that component's props to change, which triggers a re-render.

componentDidMount() not working for my entire application. This is one of the many components not rendering their results on my page

import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions';
class Signout extends Component {
componentDidMount() {
this.props.signout();
}
render() {
return <div>
Sorry to see you go
</div>
}
};
export default connect(null, actions)(Signout);
This is not rendering the page to show sorry to see you go. When I click on the link to this component I just get an empty blank page. Several other of my components experience the same thing. Only components that don't need anything from the ComponenDidMount function work on the app.
The component is called from here:
import Dashboard from "../views/Dashboard/Dashboard.jsx";
import TagTable from "../views/TagTable/TagTable.jsx";
// #material-ui/icons
import DashboardIcon from "#material-ui/icons/Dashboard";
import Apps from "#material-ui/icons/Apps";
import SignOut from "../views/Auth/Signout";
var dashRoutes = [
{
path: "/dashboard",
name: "Dashboard",
icon: DashboardIcon,
component: Dashboard
},
{
path: "/tags",
name: "Tags",
icon: Apps,
component: TagTable
},
{
path: "/logout",
name: "Logout",
icon: Apps,
component: SignOut
},
{ redirect: true, path: "/", pathTo: "/dashboard", name: "Dashboard" }
];
export default dashRoutes;
The action call is as follows:
export const signout = () => {
localStorage.removeItem('token');
return {
type: AUTH_USER,
payload: ''
};
}
Try doing this.
return (
<div>
Sorry to see you go
</div>
)
Enclose your divs inside parenthesis.
Hum! Put the text inside h1 tags or p tags instead of divs.

Get navigation props in an independent component React Native

My app.js file looks like this
export default class App extends React.Component {
render() {
return (
<Root style={{
flex: 1
}}>
<FcmHandler/>
</Root>
)
}
}
The Root component is where the entire app resides along with all the functionality, the FcmHandler is where I handle functionality related to notifications etc. Within the FcmHandler I have a method that gets a callback when a notification is clicked, inside this callback I need to navigate to a specific screen in the app based on the notification click.
The problem is using the current code above the FcmHandler component never even gets initialized.
If I try something like this
export default class App extends React.Component {
render() {
return (
<View style={{
flex: 1
}}>
<Root/>
<FcmHandler/>
</View>
)
}
}
the FcmHandler component gets called but I do not have any access to navigation props which reside inside the <Root/> component.
The <Root/> component consists of the following
const ArticleStack = StackNavigator(
{
...
}
);
const SettingsStack = StackNavigator({
...
});
export const Root = StackNavigator({
Articles: {
screen: ArticleStack
},
Settings: {
screen: SettingsStack
},
}, {
mode: 'modal',
headerMode: 'none'
});
The basic goal I am trying to achieve is, when a notification is click, irrespective of which screen the app is currently on I should be able to navigate to a particular screen. I do not want to write the navigation code in every screen component that I have, that seems redundant.
You can follow this official guide to create your navigation service. Then use the navigation service in FcmHandler instead of navigation prop. This way there is no need to put FcmHandler as a child of the navigator.
If you are using redux or mobx, it's better to move your navigation state to the store for easier access. For redux, there is an official integration guide. For mobx, you can try this.
For react-navigation users, a really cool way is to create your own Navigation Service
You can initialize your Navigation Service module, during the time initializing your navigation store as mentioned in their docs
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
addListener,
})} />
// Just add another line to config the navigator object
NavigationService.configNavigator(dispatch) <== This is the important part
NavigationService.js
import { NavigationActions } from 'react-navigation'
let config = {}
const configNavigator = nav => {
config.navigator = nav
}
const reset = (routeName, params) => {
let action = NavigationActions.reset({
index: 0,
key: null,
actions: [
NavigationActions.navigate({
type: 'Navigation/NAVIGATE',
routeName,
params,
}),
],
})
config.navigator(action)
}
const navigate = (routeName, params) => {
let action = NavigationActions.navigate({
type: 'Navigation/NAVIGATE',
routeName,
params,
})
config.navigator(action)
}
const navigateDeep = actions => {
let action = actions.reduceRight(
(prevAction, action) =>
NavigationActions.navigate({
type: 'Navigation/NAVIGATE',
routeName: action.routeName,
params: action.params,
action: prevAction,
}),
undefined
)
config.navigator(action)
}
const goBack = () => {
if (config.navigator) {
let action = NavigationActions.back({})
config.navigator(action)
}
}
export default {
configNavigator,
navigateDeep,
navigate,
reset,
goBack,
}
Explanation :
The config initializes the navigator's dispatch object whenever your redux-navigation gets initialzed, therefore you can dispatch any navigation action, wrt the method's present in the Service Component.
Use
NavigationServices.navigate('ScreenName')
Update:
React Navigation now provides a HOC wrapper withNavigation, that passes the navigation prop into a wrapped component.
It's useful when you cannot pass the navigation prop into the component directly, or don't want to pass it in case of a deeply nested child.
Usage is well mentioned in their docs.
After a bit of research, the easiest way I found was to follow their official documentation:
I created a RootNavigation.js file in the ./misc folder;
import * as React from 'react';
export const navigationRef = React.createRef();
export function navigate(name, params) {
navigationRef.current?.navigate(name, params);
}
I imported it into App.js and created a reference to it in the return function:
import React from 'react'
import { NavigationContainer } from '#react-navigation/native';
import { createStackNavigator } from '#react-navigation/stack';
import { navigationRef } from './misc/rootNavigation'; <- navigationRef is imported
…
const Stack = createStackNavigator();
function App() {
return (
<Provider store={store}>
<NavigationContainer ref={navigationRef}> <— reference to navigationRef
<Stack.Navigator>
…
<Stack.Screen
name="Screen"
component={Screen}
options={{
title: “Hello”,
headerLeft: () => <ScreenButton/>
}} />
</Stack.Navigator>
</NavigationContainer>
</Provider>
);
}
export default App
I called it inside the ScreenButton component
import React, { Component } from 'react'
…
import * as RootNavigation from '../misc/rootNavigation'; <—- imported
class RoomButton extends Component {
constructor(props) {
super(props)
}
render() {
return (
<TouchableOpacity onPress={
() => {RootNavigation.navigate( 'RoomSelectorScreen' ) <—- called here
…
</TouchableOpacity>
)
}
}

Resources