I'm having a hard time trying to make ra-tree-ui-materialui work following this doc :
https://github.com/marmelab/react-admin/blob/master/packages/ra-tree-ui-materialui/README.md
I already have a react-admin backoffice with some fixture data, and I decided, after editing my App.js like explained in link above, to put my tree logic inside SegmentationList.js, which manages display of all Segmentations coming from an APIPlatform backend.
I commented datagrid logic already present in file, to test the tree alone. I kept all imports active and added those needed for the tree like in docs. With this code I manage to have the tree displayed, but with no hierarchy view at all, even when I set a row as child of another by editing, or when I do it via drag and drop.
When I try the latter, I actually view the child row nested inside its parent with collapse button for a few seconds only. Then it comes back to a flat tree.
I have tried to disable JSS in the file to see if style was guilty. I checked if react-dnd was installed and it is. I checked that parent field had value expected in child row by coming back to its edit page. Finally I went to backend side to check if parent field values in DB were consistent with what I saw in frontend, it was. Finally I had a look on this topic : https://github.com/marmelab/react-admin/issues/2980 since I also have the warning "Missing translation for key: "ra.tree.root_target"".
Thanks for your help.
First, here is my App.js file :
import React, {Component} from 'react';
import { Admin, Resource, mergeTranslations } from 'react-admin';
import { reducer as tree } from 'ra-tree-ui-materialui';
import englishMessage from 'ra-language-english';
import treeEnglishMessages from 'ra-tree-language-english';
import parseHydraDocumentation from '#api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation';
import { hydraClient } from '#api-platform/admin';
import Locale from "./Resources/Locale/"
import Segmentation from "./Resources/Segmentation/"
import SegmentationTranslation from "./Resources/SegmentationTranslation/"
import Product from "./Resources/Product/"
import Attribute from "./Resources/Attribute/"
import ProductTranslation from "./Resources/ProductTranslation/"
import translations from './i18n';
import CustomRoute from './routes';
import themeReducer from './themeReducer';
import { Layout } from './layout';
import LocaleRetrieve from './Utils/LocaleRetrieve';
const messages = {
'en': mergeTranslations(englishMessage, treeEnglishMessages),
};
const dataProvider = api => hydraClient(api);
const httpEndpoint = process.env.REACT_APP_XXX_HTTP;
const apiDocumentationParser = httpEndpoint => parseHydraDocumentation(httpEndpoint)
.then(
({ api }) => ({api})
);
const i18nProvider = locale => {
// change of locale after initial call returns a promise
return translations[locale];
}
export default class extends Component {
state = { api: null };
componentDidMount() {
apiDocumentationParser(httpEndpoint).then(({ api }) => {
this.setState({ api });
}).catch((e) => {
console.log(e);
});
console.log(LocaleRetrieve());
};
render() {
if (null === this.state.api) return <div>Loading...</div>;
return (
<Admin api={ this.state.api }
apiDocumentationParser={ apiDocumentationParser }
dataProvider= { dataProvider(this.state.api) }
customReducers={{theme: themeReducer, tree}}
messages={translations}
locale="en"
i18nProvider={i18nProvider}
title="XXX"
customRoutes={CustomRoute}
appLayout={Layout}
>
<Resource name="locales" {...Locale} />
<Resource name="segmentations" {...Segmentation} />
<Resource name="segmentation_translations" {...SegmentationTranslation}/>
<Resource name="products" {...Product}/>
<Resource name="product_translations" {...ProductTranslation}/>
<Resource name="attributes" {...Attribute}/>
</Admin>
)
}
}
and here is my component with tree logic, located in src/Resources/Segmentation/SegmentationList.js :
import React, {Fragment} from 'react';
import {List, Datagrid, TextField, ChipField, BooleanField, ReferenceField, EditButton, ReferenceInput, AutocompleteInput, ShowButton, Filter, TextInput, Labeled, CardActions, ExportButton, RefreshButton, DeleteButton, SaveButton } from 'react-admin';
import LinkToTranslatations from './LinkToTranslations';
import AddChildButton from "./AddChildButton";
import ListChildButton from "./ListChildButton";
import PublishedButtons from './PublishedButtons';
import CreateSegmentationButtons from './CreateSegmentationButtons';
// for tree
import { withStyles } from '#material-ui/core/styles';
import { IgnoreFormProps, Tree, NodeForm, NodeActions, NodeView } from 'ra-tree-ui-materialui';
const styles = {
hash: {
marginLeft: '15px',
fontWeight: 'bold',
marginRight: '15px'
},
type: {
marginLeft: '15px',
marginRight: '15px',
textTransform: 'uppercase'
},
title: {
marginLeft: '15px',
marginRight: '15px'
}
};
// for tree
const SegmentationTreeActions = props => (
<NodeActions {...props}>
<LinkToTranslatations />
<ShowButton />
<IgnoreFormProps>
<EditButton />
<DeleteButton />
</IgnoreFormProps>
</NodeActions>
);
// tree
export const SegmentationList = withStyles(styles)(({ classes, ...props}) => (
<List {...props} perPage={10000}>
<Tree allowDropOnRoot enableDragAndDrop>
<NodeView actions={<SegmentationTreeActions />}>
<TextField source="hash" className={classes.hash} />
<TextField source="type" className={classes.type} />
<TextField source="title" className={classes.title} />
</NodeView>
</Tree>
</List>
));
export default SegmentationList;
Related
Problem
I am new to React Native. Recently I faced with such a problem: when I move from the login screen to the signup screen, the signup screen is loaded again each time. How I can load the screen only once and store it in RAM or do something like that, to avoid rerendering? How to add and remove screens to RAM manually through code.
Environment
MacOS 13.0.1 (M1)
React Native CLI
dependencies:
#react-navigation/native: ^6.1.2,
#react-navigation/stack: ^6.3.11,
expo-linear-gradient: ^12.0.1,
react: 18.1.0,
react-native: ^0.70.6,
react-native-color-picker: ^0.6.0,
react-native-event-listeners: ^1.0.7,
react-native-gesture-handler: ^2.9.0,
react-native-localization: ^2.3.1,
react-native-paper: ^5.1.3,
react-native-paper-dropdown: ^1.0.7,
react-native-safe-area-context: ^4.4.1,
react-native-screens: ^3.19.0,
react-native-vector-icons: ^9.2.0,
Code
App.navigator.tsx
import React from "react"
import { createStackNavigator, StackView } from "#react-navigation/stack"
import { NavigationContainer } from "#react-navigation/native"
import { SignupScreen } from "./screens/signup/signup.screen"
import { LoginScreen } from "./screens/login/login.screen"
import { HomeScreen } from "./screens/home/home.screen"
import { SettingsScreen } from "./screens/settings/settings.screen"
const Stack = createStackNavigator()
// App navigation. Used to relocate between the app's screens
const AppNavigator = () => (
<NavigationContainer>
<Stack.Navigator screenOptions={{headerShown: false,
headerMode: "screen",
cardStyle: {backgroundColor: "white"}}}
initialRouteName="Login">
<Stack.Screen name="Login"
component={LoginScreen} />
<Stack.Screen name="SignUp"
component={SignupScreen} />
<Stack.Screen name="Home"
component={HomeScreen} />
<Stack.Screen name="Settings"
component={SettingsScreen} />
</Stack.Navigator>
</NavigationContainer>
)
export default AppNavigator
App.tsx
import React, {useState, useEffect} from 'react';
import {Provider as PaperProvider} from 'react-native-paper';
import { EventRegister } from 'react-native-event-listeners';
import AppNavigator from './app.navigator';
import mainAppTheme, {fontTheme} from './config/theme';
import themeContext from './config/themeContext';
import { CHANGE_THEME_LITERAL } from './config/theme';
const App = () => {
// Theme update
const [theme, setTheme] = useState(mainAppTheme)
useEffect(() => {
let eventListener = EventRegister.addEventListener(CHANGE_THEME_LITERAL, (theme) => {
setTheme(theme)
})
return () => {
EventRegister.removeEventListener(eventListener.toString())
}
})
return (
<themeContext.Provider value={theme}>
<PaperProvider theme={fontTheme}>
<AppNavigator />
</PaperProvider>
</themeContext.Provider>
);
};
export default App;
Login.screen.tsx
import React, { useContext, useState } from "react";
import { SafeAreaView, View } from "react-native";
import { Button, Card, TextInput } from "react-native-paper";
import { PasswordComponent } from "../../components/password.component";
import mainAppTheme, {appTheme} from "../../config/theme";
import themeContext from "../../config/themeContext";
import { loginScreenTrans } from "../../translations/login.screen.trans"
import { loginStyle } from "./login.style";
interface LoignScreenProps{
navigation: any
}
// Login app screen. Meets new users
export const LoginScreen = (props:LoignScreenProps) => {
// Theme update
const theme: appTheme = useContext(themeContext)
loginScreenTrans.setLanguage(theme.lang)
return(
<SafeAreaView style={loginStyle().content}>
<View style={loginStyle().view}>
<Card>
<Card.Title title="BuildIn" titleStyle={loginStyle().cardTitle}></Card.Title>
<Card.Content>
<TextInput selectionColor={theme.colors.mainAppColor}
activeUnderlineColor={theme.colors.mainAppColor}
label={loginScreenTrans.email}
keyboardType="email-address"
style={loginStyle().email} />
<PasswordComponent label={loginScreenTrans.password}
color={theme.colors.mainAppColor.toString()}
style={loginStyle().password}/>
<Button uppercase={false}
textColor={theme.colors.mainAppTextColor}>
{loginScreenTrans.forgot}
</Button>
<Button buttonColor={theme.colors.mainAppColor}
textColor={"#ffffff"}
uppercase={true}
mode="contained"
onPress={() => {props.navigation.navigate("Home");
props.navigation.reset({
index: 0,
routes: [{ name: 'Home' }]})
}}>
{loginScreenTrans.login}
</Button>
<Button uppercase={true}
textColor={mainAppTheme.colors.mainAppTextColor}
onPress={() => props.navigation.navigate("SignUp")}>
{loginScreenTrans.signup}
</Button>
</Card.Content>
</Card>
</View>
</SafeAreaView>
);
}
What i tried
Next steps changed nothing in my case:
Use enableFreeze(true) and enableScreens(true) at the top of loaded screen file and top of navigation file.
Wrap my screen in React.memo()
Set freezeOnBlur: true prop into <Stack.Navigator>
navigation.dispatch(CommonActions.reset({ routes[...]
Maybe I used it incorrectly, I would be grateful if someone could explain to me why.
But it seems that the problem is specifically in the way react navigation works. And I don't know how to set it up the way I want.
I have a react-admin App with multiple list resources and would want to only clear the filter when I change between lists (switching between companies/rules/lookups). Currently I am using the solution shown in RuleList.js for each list (RuleFilter part). This however also resets the filter every time you show/edit an element in the list. I don't know if there is a way to detect when you click between companies/rules/lookups that you could use to clear the filter.
App.js
import * as React from "react"
import { Admin, Resource } from 'react-admin'
import dataProvider from './dataProvider'
import companies from './companies'
import rules from './rules'
import lookups from './lookups'
const App = () => (
<Admin
dataProvider={dataProvider}>
<Resource name="companies" {...companies} />
<Resource name="rules" {...rules} />
<Resource name="lookups" {...lookups} />
</Admin>
)
export default App
RuleList.js
import React, { useState, useEffect } from 'react'
import { List, Datagrid, TextField, EditButton } from 'react-admin'
const RuleFilter = (props) => {
useEffect(() => {
const { setFilters } = props
return () => setFilters({ regex: '' })
}, [])
return (
<Filter {...props}>
<TextInput label="Search" source="regex" alwaysOn />
</Filter>
)
}
const RuleList = (props) => {
return (
<List {...props}
filters={<RuleFilter />}
exporter={false}>
<Datagrid rowClick="edit">
<TextField source="id" />
<TextField source="regex" />
<EditButton />
</Datagrid>
</List>
)
}
export default RuleList
index.js for Rule
import RuleList from'./RuleList'
import RuleEdit from './RuleEdit'
import RuleCreate from './RuleCreate'
const rules = {
list: RuleList,
edit: RuleEdit,
create: RuleCreate,
}
export default rules
Clear the search field when clicking companies or rules
Use redux-persist, and save your filters in Store,
OR
Use localStorage to save your filters
I am trying to create a custom hook to be able to open and close a pop-out menu with conditional rendering using style display: none and display:block. I think I understand how to share the state between the components (I can console log that and get that working) , but I can not figure out how to update the state using the hook.
I am certain that I have some fundamental misunderstanding here but if anyone can clarify what it is I am trying to achieve that would be awesome! I have tried to learn this for several nights and here is where I have got to.
This is the header of the pop out menu it only contains a close button at the moment
import React from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faWindowClose } from '#fortawesome/free-solid-svg-icons'
import useOpenCloseElementMenu from '../Hooks/openCloseElementMenu'
function ElementMenuHeader() {
const { elementMenuOpenClose, setElementMenuOpenClose } = useOpenCloseElementMenu();
return (
<div id="App-Close-Element-Menu-Container">
<button id="App-Close-Element-Menu"
onClick={() => setElementMenuOpenClose(false) }
>
<FontAwesomeIcon icon={faWindowClose} />
</button>
</div>
);
}
export default ElementMenuHeader
This is the pop out menu
import React from 'react';
import SizerGroup from '../Sizer/sizerGroup';
import './element-menu.css';
import ElementMenuHeader from './element-menu-header';
import TitleWithLine from './title-with-line';
import TypeSelector from './type-selector';
import TemplateSelector from './template-selector';
import useOpenCloseElementMenu from '../Hooks/openCloseElementMenu'
function Editor(props) {
const { elementMenuOpenClose, setElementMenuOpenClose } = useOpenCloseElementMenu();
console.log(elementMenuOpenClose);
return (
<div className="App-Element-Menu"
style={{display: elementMenuOpenClose ? 'block' : 'none' }}
>
<ElementMenuHeader />
<TitleWithLine title="Element size" />
<SizerGroup />
<TitleWithLine title="Elements" />
<TypeSelector />
<TitleWithLine title="Templates" />
<TemplateSelector />
</div>
);
}
export default Editor
This is the toolbar that has the open menu button
import React from 'react'
import Button from '../Button/button'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faBoxes } from '#fortawesome/free-solid-svg-icons'
import './toolbar.css'
import useOpenCloseElementMenu from '../Hooks/openCloseElementMenu'
function Toolbar(props) {
const { toolbar_show_or_hide } = props
const elementMenuIcon = <FontAwesomeIcon icon={ faBoxes } />
const { elementMenuOpenClose, setElementMenuOpenClose } = useOpenCloseElementMenu();
const openEditor = setElementMenuOpenClose[true]
return (
<div className="App-Toolbar" style={{ display: toolbar_show_or_hide ? "flex" : "none" }} >
<Button
id="App-Open-Element-Menu-Button"
icon={ elementMenuIcon }
useToolTip={ true }
toolTipText="Elements menu. Select elements to populate the theme."
buttonFunction={ openEditor }
/>
</div>
)
}
export default Toolbar
This is the hook
import React, { useState } from 'react';
const useOpenCloseElementMenu = () => {
const [elementMenuOpenClose, setElementMenuOpenClose] = useState(false);
return { elementMenuOpenClose, setElementMenuOpenClose };
};
export default useOpenCloseElementMenu;
I feel you donot have to pass the hook in a separate function, useOpenCloseElementMenu, like you did.
Instead of importing the ../Hooks/openCloseElementMenu function thing,
I'd rather just call the hooks directly instead as
const [elementMenuOpenClose, setElementMenuOpenClose] = useState(false);
in the editor and toolbar component in place of const { elementMenuOpenClose, setElementMenuOpenClose } = useOpenCloseElementMenu();.
Also which component did you use the toolbar component if I may ask? Because I don't seem to see any of that here...It confusing where it got the toolbar_show... props from.
{I hope this helps cause that seem like the most obvious reason}
I am using material UI with React. I have a modal component and a ButtonAppBar. Inside the ButtonAppBar there is a shopping cart icon that I added. I am still a bit new to React and would like to know the best way to display the modal when the shopping cart is clicked. Thanks in advance.
So here is my App.js:
import React, { Component } from 'react';
import { BrowserRouter } from 'react-router-dom';
import { Route } from 'react-router-dom';
import './App.css';
import ShopHome from './containers/ShopHome';
import ButtonAppBar from './components/ButtonAppBar';
import SimpleModalWrapped from './containers/ShoppingCartModal';
class App extends Component {
handle
render() {
return (
<BrowserRouter>
<div>
<ButtonAppBar />
<SimpleModalWrapped />
<Route exact path="/" component={ShopHome} />
</div>
</BrowserRouter>
);
}
}
export default App;
Here is my ButtonAppBar:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import SvgIcon from '#material-ui/core/SvgIcon';
import ShoppingCart from '#material-ui/icons/ShoppingCart';
const styles = {
root: {
flexGrow: 1,
},
grow: {
flexGrow: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
},
appBar: {
marginBottom: 50,
}
};
function ButtonAppBar(props) {
const { classes } = props;
return (
<div className={classes.root}>
<AppBar style={styles.appBar} position="static">
<Toolbar>
<IconButton className={classes.menuButton} color="inherit" aria-label="Menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" className={classes.grow}>
Velo-Velo
</Typography>
<Button color="inherit">Checkout</Button>
<SvgIcon>
<ShoppingCart />
</SvgIcon>
</Toolbar>
</AppBar>
</div>
);
}
ButtonAppBar.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(ButtonAppBar);
Here is the modal:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import Modal from '#material-ui/core/Modal';
import Button from '#material-ui/core/Button';
function rand() {
return Math.round(Math.random() * 20) - 10;
}
function getModalStyle() {
const top = 50 + rand();
const left = 50 + rand();
return {
top: `${top}%`,
left: `${left}%`,
transform: `translate(-${top}%, -${left}%)`,
};
}
const styles = theme => ({
paper: {
position: 'absolute',
width: theme.spacing.unit * 50,
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[5],
padding: theme.spacing.unit * 4,
},
});
class SimpleModal extends React.Component {
state = {
open: false,
};
handleOpen = () => {
console.log('clicked')
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
const { classes } = this.props;
return (
<div>
{/* <Typography gutterBottom>Click to get the full Modal experience!</Typography>
<Button onClick={this.handleOpen}>Open Modal</Button> */}
<Modal
aria-labelledby="simple-modal-title"
aria-describedby="simple-modal-description"
open={this.state.open}
onClose={this.handleClose}
>
<div style={getModalStyle()} className={classes.paper}>
<Typography variant="h6" id="modal-title">
Text in a modal
</Typography>
<Typography variant="subtitle1" id="simple-modal-description">
Duis mollis, est non commodo luctus, nisi erat porttitor ligula.
</Typography>
<SimpleModalWrapped />
</div>
</Modal>
</div>
);
}
}
SimpleModal.propTypes = {
classes: PropTypes.object.isRequired,
};
// We need an intermediary variable for handling the recursive nesting.
const SimpleModalWrapped = withStyles(styles)(SimpleModal);
export default SimpleModalWrapped;
Your best bet is to use something like Redux. As a lazier strategy have a Higher Order Component house both components. The higher order component can have the function which needs to run when you click on the icon and it changes something in the state of the higher order Component.
Say you have:
import React, { Component } from 'react'
import ComponentWithIcon from './icon-holder'
import ModalComponent from './modal'
class OuterContainer extends Component {
state = { modalOpen: false }
setModal = openOrClose => this.setState({modalOpen: openOrClose})
render(){
const {setModal, state: { modalOpen } } = this
return (
<>
<ComponentWithIcon
handleModalClick={setModal}
/>
<ModalComponent
isOpen={modalOpen}
handleModalClick={setModal}
/>
</>
)
}
}
As a result rather than the Modal component determining whether it is open (having it in its own state) which means that only it will know about whether it is presently open that will be determined by the OuterContainer... The OuterContainer is also the one which will handleTheClickEvent which clicking on the icon causes, so instead of running its own function, the icon will run the OuterComponent's function to setState...
This functionality (the clickHandler) and the state is passed to each of those child components through their props. Since the modal needs to be able to close that too can be passed in from the OuterComponent and it can be kept with the same state.modalOpen and possibly the same passed in action (clickHandler) which is toggle (or if you need for some reason then you can have an openModal/closeModal defined by the OuterComponent and pass both of those callbacks to be run by the modal.
Using redux (with react-redux) you have a single <Provider> component which is the higher order components to all of its children. The provider keeps in state a general store which is generated through redux's createStore() this store then gets actions which manipulate the central store and because it is at the top level it is able to inject its current state (or specific parts of it) to any component that is held within the Provider (which is every single component). Each of those components are able to send messages to that provider using dispatch() they then dispatch actions to the store and that results in the store being replaced with a new store that has things updated inside of it (such as whether the modal is open).
import React from 'react'
const MyModal = ({isOpen, handleModal }) => (
<div className={`modal ${isOpen ? 'is-showing' : 'is-hidden'}`}>
<div
className='toolbar'
>
<CloseButton onClick={() => handleModal(false)} />
</div>
<div>
{/* Modal content */}
</div>
</>
)
So I'm still a bit new to React Native, but I've got an app working nearly how I want it to. I have App.js which uses the TabBarIOS component to display my tabbed navigation at the bottom of the screen. When you touch a tab, the state updates and the relevant content is loaded and displayed:
App.js
import React, { Component } from 'react';
import { TabBarIOS, Platform, Image } from 'react-native';
import IconII from 'react-native-vector-icons/Ionicons';
import IconMCI from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from './Colors';
import RouterItem1 from './routers/RouterItem1';
import RouterItem2 from './routers/RouterItem2';
import RouterHome from './routers/RouterHome';
import Settings from './components/Settings';
class FooterNav extends Component {
state = {
selectedTab: 'home',
};
handleClick = (routeData) => {
console.log('This has received data', routeData);
this.setState({ selectedTab: routeData });
console.log(this.state);
}
renderCurrentView() {
switch (this.state.selectedTab) {
case 'home':
return (
<RouterHome handleClick={this.handleClick} />
);
case 'item2':
return (
<RouterItem2 />
);
case 'item1':
return (
<RouterItem1 />
);
case 'settings':
return (
<Settings />
);
default:
return false;
}
}
render() {
return (
<TabBarIOS
unselectedTintColor={Colors.third} //Unselected labels
unselectedItemTintColor={Colors.third} //Unselected icons
tintColor={Colors.brandPrimary} //Selected
barTintColor={Colors.light} //Bar background
>
<IconII.TabBarItem
title="Home"
iconName="ios-home-outline"
selectedIconName="ios-home"
selected={this.state.selectedTab === 'home'}
receiveData={this.receiveData}
onPress={() => {
this.setState({
selectedTab: 'home',
});
}}
>
{this.renderCurrentView()}
</IconII.TabBarItem>
<TabBarIOS.Item
icon={require('./images/item2-icon-line#3x.png')}
selectedIcon={require('./images/item2-icon-selected#3x.png')}
title="item2"
selected={this.state.selectedTab === 'item2'}
onPress={() => {
this.setState({
selectedTab: 'item2',
});
}}
>
{this.renderCurrentView()}
</TabBarIOS.Item>
<IconMCI.TabBarItem
title="item1"
iconName="cookie"
selectedIconName="cookie"
selected={this.state.selectedTab === 'item1'}
onPress={() => {
this.setState({
selectedTab: 'item1',
});
}}
>
{this.renderCurrentView()}
</IconMCI.TabBarItem>
<IconII.TabBarItem
title="More"
iconName="ios-more-outline"
selectedIconName="ios-more"
selected={this.state.selectedTab === 'settings'}
onPress={() => {
this.setState({
selectedTab: 'settings',
});
}}
>
{this.renderCurrentView()}
</IconII.TabBarItem>
</TabBarIOS>
);
}
}
module.exports = FooterNav;
react-native-router-flux is a great plugin, once it pulls in a router the flow is exactly what I want it to be. The only problem I have is with the <RouterHome> module:
RouterHome.js
import React from 'react';
import { Scene, Router } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
import AnotherScene from '../components/pages/AnotherScene';
import Home from '../components/Home';
const RouterHomeComponent = () => {
return (
<Router
sceneStyle={styles.sceneStyle}
navigationBarStyle={styles.navBar}
titleStyle={styles.navBarTitle}
barButtonIconStyle={styles.barButtonIconStyle}
>
<Scene
key="Home"
component={Home}
title={content.heading}
hideNavBar
/>
<Scene
key="AnotherScene"
component={AnotherScene}
title='title'
hideNavBar={false}
/>
</Router>
);
};
export default RouterHomeComponent;
The default view that is loaded is the <Home> module:
Home.js
import React, { Component } from 'react';
import { Text, View, TouchableOpacity } from 'react-native';
import { Actions } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
class Home extends Component {
displayItem1 = () => {
this.props.handleClick('item1');
}
displayItem2 = () => {
this.props.handleClick('item2');
}
displayAnotherScene() {
Actions.AnotherScene();
}
render() {
return (
<View style={styles.viewWrapperHome}>
<Text style={styles.heading}>{content.greeting}</Text>
<TouchableOpacity onPress={this.displayItem1}>
<Text>First item</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.displayItem2}>
<Text>Second item</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.displayAnotherScene}>
<Text>Another scene</Text>
</TouchableOpacity>
</View>
);
}
}
export default Home;
So what I expect to happen is that if the user clicks on the first two buttons displayed on the screen (First item/Second item), the prop will be passed back to App.js, the state will change and the scene will be updated. It basically is an alternative way of navigating without using the footer menu.
I know that this would work without using the react-native-router-flux module as I had it running before I added it in. The problem is that I really need it to handle the other pages from the <Home> module (many more to add).
Can anyone suggest a way I can pass back the props through the router back to my App.js?
Okay, so I actually figured this out - it turned out to totally be my fault; the props weren't getting passed to RouterHome and so they got lost either side. The new RouterHome looks like this:
RouterHome.js
import React from 'react';
import { Scene, Router } from 'react-native-router-flux';
import styles from '../Styles';
import { content } from '../content.js';
import AnotherScene from '../components/pages/AnotherScene';
import Home from '../components/Home';
const RouterHomeComponent = (props) => { <---Didn't add props
return (
<Router
sceneStyle={styles.sceneStyle}
navigationBarStyle={styles.navBar}
titleStyle={styles.navBarTitle}
barButtonIconStyle={styles.barButtonIconStyle}
>
<Scene
key="Home"
component={Home}
title={content.heading}
hideNavBar
handleClick={props.handleClick} <---Didn't pass props
/>
<Scene
key="AnotherScene"
component={AnotherScene}
title='title'
hideNavBar={false}
/>
</Router>
);
};
export default RouterHomeComponent;
I've marked the two changes I made. Hopefully this will help someone! :)