render component based on state in react native - javascript

I am using react-native-side-menu for the menu in the app. Since this module using state to control the clicked menu, I would like to used it to render the component as well.
I am referred to this solution But it is not working, I got
Expected a component class, got [object Object].
This is what I did:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
} from 'react-native';
import Menu from './menu';
import SideMenu from 'react-native-side-menu';
import First from './first';
import Second from './second';
module.exports = class Main extends Component {
state = {
isOpen: false,
selectedItem: 'First',
};
toggle() {
this.setState({
isOpen: !this.state.isOpen,
});
}
updateMenuState(isOpen) {
this.setState({ isOpen, });
}
onMenuItemSelected = (item) => {
this.setState({
isOpen: false,
selectedItem: item,
});
}
render() {
const menu = <Menu onItemSelected={this.onMenuItemSelected} />;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={(isOpen) => this.updateMenuState(isOpen)}
>
<this.state.selectedItem />
<Button style={styles.button} onPress={() => this.toggle()}>
<Image
source={require('./assets/menu.png')} style={{width: 32, height: 32}} />
</Button>
</SideMenu>
);
}
}
....
UPDATE
Thanks for #NaderDabit suggest. Yes indeed, I should use
selectedItem: <First />,
instead.

Related

Custom input component in react native input is not working as expected

I am trying to make a custom input component with onChangeText but whenever I start typing in the textInput box I get an error. I have checked the code many times and everything looks fine to me.
import React from "react";
import { TextInput, StyleSheet } from "react-native";
const defaultInput = props => (
<TextInput
underlineColorAndroid="transparent"
{...props}
style={[styles.input, props.style]}
/>
)
const styles = StyleSheet.create({
input: {
width: "100%",
borderWidth: 1,
borderColor: "#eee",
padding: 5,
marginTop: 8,
marginBottom: 8
}
});
export default defaultInput;
This is my sub component where I am using my custom component.
import React, { Component } from "react";
import { View, TextInput, Button, StyleSheet } from "react-native";
import DefaultInput from "../UI/DefaultInput/DefaultInput";
const placeInput = props =>(
<DefaultInput
placeholder="Place Name"
value={props.placeName}
onChangeText={props.onChangeText}
/>
)
export default placeInput;
This is the screen where I am using my sub component.
import React, { Component } from 'react'
import { Text, View, TextInput, Button, StyleSheet, ScrollView, Image } from 'react-native'
import { connect } from 'react-redux'
import placeImage from '../../asset/pic.jpg'
import PlaceInput from '../../component/PlaceInput/PlaceInput'
import { addPlace } from '../../store/actions/index'
import { Navigation } from 'react-native-navigation'
// import DefaultInput from '../../component/UI/DefaultInput/DefaultInput'
import HeadingText from '../../component/UI/HeadingText/HeadingText'
import MainText from '../../component/UI/MainText/MainText'
import PickImage from '../../component/PickImage/PickImage'
import PickLocation from '../../component/PickLocation/PickLocation'
class SharePlace extends Component {
state={
placeName:""
}
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(this.OnNavigatorEvent);
}
placeNameChangedHandler = val => {
this.setState({
placeName: val
});
};
OnNavigatorEvent = (event) => {
console.log(event);
if (event.type === "NavBarButtonPress") {
if (event.id === "sideDrawerToggle") {
this.props.navigator.toggleDrawer({
side: "left"
})
}
}
}
placeAddedHandler = () => {
if(this.state.placeName.trim() !== "")
{
this.props.onAddPlace(this.state.placeName);
}
}
render() {
return (
// <ScrollView contentContainerStyle={styles.conatiner}>
<ScrollView>
<View style={styles.conatiner}>
<MainText>
<HeadingText>Share a place with us!</HeadingText>
</MainText>
<PickImage />
<PickLocation />
<PlaceInput
placeName={this.state.placeName}
onChangeText={this.placeNameChangedHandler}
/>
<View style={styles.button}>
<Button title="share the place" onPress={this.placeAddedHandler} />
</View>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
conatiner: {
flex: 1,
alignItems: "center"
},
placeholder: {
borderWidth: 1,
borderColor: "black",
backgroundColor: "#eee",
width: "80%",
height: 150
},
button: {
margin: 8
},
imagePreview: {
width: "100%",
height: "100%"
}
})
const mapDispatchToProps = dispatch => {
return {
onAddPlace: (placeName) => dispatch(addPlace(placeName))
}
}
export default connect(null, mapDispatchToProps)(SharePlace)
This is the error I am getting.
ExceptionsManager.js:63 Invariant Violation: TextInput(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
This error is located at:
in TextInput (at DefaultInput.js:5)
in defaultInput (at PlaceInput.js:7)
in placeInput (at SharePlace.js:60)
in RCTView (at View.js:60)
in View (at SharePlace.js:54)
in RCTScrollContentView (at ScrollView.js:791)
in RCTScrollView (at ScrollView.js:887)
in ScrollView (at SharePlace.js:53)
in SharePlace (created by Connect(SharePlace))
in Connect(SharePlace) (at Navigation.js:83)
in Provider (at Navigation.js:82)
in _class2 (at renderApplication.js:33)
in RCTView (at View.js:60)
in View (at AppContainer.js:102)
in RCTView (at View.js:60)
in View (at AppContainer.js:122)
in AppContainer (at renderApplication.js:32)
Using typescript,
import {TextInput, TextInputProps, View} from "react-native";
declare a props interface:
interface Props extends TextInputProps {}
// This ensures that all the properties associated with react-native's
// TextInput component, are associated with your custom-input component as well.
decalare your custom-input component:
const CustomInput = (props: Props) => {
<TextInput onChangeText={props.onChangeText} placeholder={props.placeholder} style={[props.style]} />
}
export default CustomInput;
use your custom-input component in LoginScreen.tsx say;
import React from "react";
import CustomInput from "../CustomInput";
const LoginScreen = () => {
const handleChange = (value: string) =>{
....
}
return(
<CustomInput placeholder="email" onChangeText={value => handleChange(value) />
)
your code working fine as the way I ran it, maybe you have problem to import PlaceInput or DefaultInput:
import React, { Component } from 'react';
import { View, Text, FlatList, ScrollView,TextInput, Image,StyleSheet } from 'react-native';
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
placeName: ""
}
}
placeNameChangedHandler = val => {
this.setState({
placeName: val
});
};
render() {
return (
<View>
<PlaceInput
placeName={this.state.placeName}
onChangeText={this.placeNameChangedHandler}
/>
</View>
);
}
}
const PlaceInput = props => (
<DefaultInput
placeholder="Place Name"
value={props.placeName}
onChangeText={props.onChangeText}
/>
)
const DefaultInput = props => (
<TextInput
underlineColorAndroid="transparent"
{...props}
style={[styles.input, props.style]}
/>
)
const styles = StyleSheet.create({
input: {
width: "100%",
borderWidth: 1,
borderColor: "#eee",
padding: 5,
marginTop: 8,
marginBottom: 8
}
});

Error when Adjacent elements with react native

I am very new with react-native and have trouble with this code:
import React, { Component, PropTypes, View } from 'react'
import { connect } from 'react-redux'
import StartupActions from '../Redux/StartupRedux'
import ReduxPersist from '../Config/ReduxPersist'
import { StackNavigator } from 'react-navigation'
import WelcomeContainer from '../Containers/WelcomeContainer'
import SettingsContainer from '../Containers/SettingsContainer'
import About from '../Components/About'
import { Header } from 'react-native-elements'
const AppNavigator = StackNavigator({
Home: {
screen: WelcomeContainer,
navigationOptions: {
title: 'Multi Language Sample App' // we advice using something static like your app's name or company name on the startup screen
}
},
Settings: {
screen: SettingsContainer,
navigationOptions: ({navigation}) => ({
title: navigation.state.params.title
})
},
About: {
screen: About,
navigationOptions: ({navigation}) => ({
title: navigation.state.params.title
})
}
})
class RootContainer extends Component {
componentDidMount() {
if (!ReduxPersist.active) {
this.props.startup()
}
}
render() {
return (
<View>
<AppNavigator />
<AppNavigator />
</View>
)
}
}
const mapStateToDispatch = dispatch => ({
startup: () => dispatch(StartupActions.startup())
})
export default connect(null, mapStateToDispatch)(RootContainer)
RootContainer.propTypes = {
startup: PropTypes.func.isRequired
}
I get the error : Adjacent JSX elements must be wrapped in an enclosing tag.
I found different posts with the same issue but was not able to solve my problem.
Enclose you code inside view or another parent element.
render() {
return (
<View>
<AppNavigator />
<Button
large
icon={{name: 'envira', type: 'font-awesome'}}
title='LARGE WITH RIGHT ICON' />
</View>
)
}
}
In react you need to return a single component/element in your render method.
render() {
return (
<View>
<AppNavigator />
<Button
large
icon={{name: 'envira', type: 'font-awesome'}}
title='LARGE WITH RIGHT ICON'
/>
</View>
)
}
}
Since v0.16 of react you can return an array of elements/components. More info here.
New render return types: fragments and strings You can now return an
array of elements from a component’s render method. Like with other
arrays, you’ll need to add a key to each element to avoid the key
warning
render() {
return (
[<AppNavigator />, <Button large icon={{name: 'envira', type: 'font-awesome'}} title='LARGE WITH RIGHT ICON' />]
)
}
}

How to access state when passing parameters using Stack Navigator in React Native

I've been working on my first React Native project. It is a Multiscreen App, and one of the screens requires some data, which I'm passing from the parent screen. But the issue is that when I receive the data in the child screen, and try to save the value in the screen's state, the app crashes. As soon as I remove the code that accesses the state, it does not crash. Here's the code:
renderRow(object) { //Calling the second screen when the user touches
const { navigate } = this.props.navigation;
return(
<TouchableOpacity onPress={() => navigate('ViewRecord', { key: object.key })}> //Sending the parameter
<Image
styleName="large-square"
source={{ uri: object.record.image }} >
<Text style={styles.designNumberHeading}>{object.record.designNumber}</Text>
</Image>
</TouchableOpacity>
);
}
Here is the code of the Child Screen:
'use-strict'
import React, { Component } from 'react';
import {
StyleSheet,
View,
KeyboardAvoidingView,
ScrollView,
TouchableHighlight,
Text,
FlatList,
} from 'react-native';
import {
Heading,
Title,
TextInput,
Button,
Image,
NavigationBar,
ListView,
TouchableOpacity,
Icon,
Lightbox,
Overlay,
} from '#shoutem/ui';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import NavBar from '../components/NavBar.js';
import { firebaseApp } from '../config/firebase.js';
export default class ViewRecord extends Component{
constructor(props) {
super(props);
this.state={
designNumber: '',
dates: [],
quantity: 0,
karigars: [],
colour:'',
amount: '',
description: '',
editMode: false,
};
this.updateStateAfterGettingData = this.updateStateAfterGettingData.bind(this);
}
getData() {
const { params } = this.props.navigation.state; //Accessing the parameters
console.log('Key: ', params.key);
let databaseRef = firebaseApp.database().ref(params.key);
databaseRef.once('value', (snap) => {
console.log('Inside Event Listener');
this.updateStateAfterGettingData(snap); //Setting the state. (The App crashes if this statement is executed)
});
}
updateStateAfterGettingData(snap) {
this.setState({
designNumber: snap.val().designNumber,
dates: snap.val().dates,
quantity: snap.val().quantity,
karigars: snap.val().karigars,
colour: snap.val().colour,
amount: snap.val().amount,
materials: snap.val().materials,
description: snap.val().description,
});
console.log(this.state);
}
render() {
const { goBack } = this.props.navigation;
this.getData();
if (!this.state.editMode) {
return(
<View style={styles.container}>
<NavBar title="View Record" hasHistory={true} goBack={() => goBack()}/>
</View>
);
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FFFFFF',
},
})
Here is the code of the StackNavigator:
import { StackNavigator } from 'react-navigation';
import CreateRecord from '../screens/CreateRecord.js';
import Records from '../screens/Records.js';
import ViewRecord from '../screens/ViewRecord.js';
export const Navigator = StackNavigator({
Records: { screen: Records },
CreateRecord: { screen: CreateRecord },
ViewRecord: { screen: ViewRecord },
},
{
headerMode: 'none',
navigationOptions: {
headerVisible: false,
}
});
Now, how can I manipulate the state of the ViewRecord.js class when accepting parameters?
PS: I am using Expo along with Create React Native App

undefined is not an object error in react native

I'm trying to create a route to a screen by pressing a button in a side menu using react navigation. When I try to implement it, I get the following error:
undefined is not an object (evaluating '_this.props.user.Range')
The error flags, point something wrong in here:
RangeValues: this.props.user.Range
The rest of the components I am trying to navigate to are here:
import React, {Component} from 'react'
import {
StyleSheet,
View,
Text,
Switch,
} from 'react-native'
import Slider from 'react-native-multislider'
export default class Profile extends Component {
state = {
RangeValues: this.props.user.Range,
distanceValue: [this.props.user.distance]
}
render() {
const {name, work, id} = this.props.user
const {RangeValues, distanceValue} = this.state
return (
<View style={styles.container}>
<View style={styles.profile}>
<Text style={{fontSize:20}}>{name}</Text>
</View>
<View style={styles.label}>
<Text>Distance</Text>
<Text style={{color:'darkgrey'}}>{distanceValue}km</Text>
</View>
<Slider
min={1}
max={100}
values={distanceValue}
onValuesChange={val => this.setState({distanceValue:val})}
onValuesChangeFinish={val => this.updateUser('distance', val[0])}
/>
<View style={styles.label}>
<Text>Age Range</Text>
<Text style={{color:'darkgrey'}}>{ageRangeValues.join('-')}</Text>
</View>
<Slider
min={1}
max={200}
values={RangeValues}
onValuesChange={val => this.setState({RangeValues:val})}
onValuesChangeFinish={val => this.updateUser('Range', val)}
/>
</View>
)
}
}
I want to navigate from a button in a drawer using stack navigator, my routing is as follows:
import { StackNavigator } from 'react-navigation';
import React from 'react';
import Home from './screens/home';
import Login from './screens/login';
import Profile from './screens/profile';
const RouteConfigs = {
Login: { screen: Login },
Home: { screen: Home },
Profile: { screen: Profile },
};
const StackNavigatorConfig = {
headerMode: 'none',
}
export default StackNavigator(RouteConfigs, StackNavigatorConfig)
Where I am trying to navigate from is the Home screen component. The function I have used for this within the Home component is:
() => this.props.navigation.navigate('Profile', { user: this.state.user })
Does anybody know how to fix this error in order for me to navigate from the home component to the profile component?
I think you should bind your props from constructor :
export class MyClass extends Component {
constructor(props) {
super(props);
if (!this.state) {
this.state = {
data: props.myData
}
}
render() {DO THE JOB HERE}
}
}
Then you can access to this.state instead of state
For more explanations, props are not yet available since the constructor has not pass. See Component doc : https://facebook.github.io/react/docs/react-component.html#constructor

React Native Element type is invalid expected a string but got undefined

I'm following a course on react-native and I just ran into this error when trying to add a modal component to a page:
Element type is invalid: expected a string(for built-in components) or a class/function (for composite components) but got: undefined.
Here's my code:
EmployeeEdit.js
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Communications from 'react-native-communications';
import { employeeUpdate, employeeSave, employeeReset } from '../actions';
import { Card, CardSection, Button, Confirm } from './common';
import EmployeeForm from './EmployeeForm';
class EmployeeEdit extends Component {
constructor(props) {
super(props);
this.state = { showModal : false};
this.onButtonPress = this.onButtonPress.bind(this);
this.onTextPress = this.onTextPress.bind(this);
}
componentWillMount() {
_.each(this.props.employee, (value, prop) => {
this.props.employeeUpdate({prop, value});
});
}
componentWillUnmount() {
this.props.employeeReset();
}
onButtonPress(){
const { name, phone, shift } = this.props;
this.props.employeeSave({ name, phone, shift, uid: this.props.employee.uid });
}
onTextPress(){
const { name, phone, shift } = this.props;
Communications.text(phone, `Hello ${name}, your upcoming shift is on ${shift}`);
}
render () {
return (
<Card>
<EmployeeForm {...this.props} />
<CardSection>
<Button onPress={this.onButtonPress}>
Save Changes
</Button>
</CardSection>
<CardSection>
<Button onPress={this.onTextPress}>
Text Schedule
</Button>
</CardSection>
<CardSection>
<Button onPress={()=> this.setState({ showModal: !this.state.showModal })}>
Fire Employee
</Button>
</CardSection>
<Confirm
visible={this.state.showModal}
>
Are you sure you want to fire this employe?
</Confirm>
</Card>
);
}
}
const mapStateToProps = (state) => {
const {name, phone, shift} = state.employeeForm;
return {name, phone, shift};
};
export default connect(mapStateToProps, {
employeeUpdate,
employeeSave,
employeeReset
})(EmployeeEdit);
Confirm.js
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { CardSection } from './CardSection';
import { Button } from './Button';
const Confirm = ({ children, visible, onAccept, onDecline }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType='slide'
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
<Text style={textStyle}>
{children}
</Text>
</CardSection>
<CardSection>
<Button onPress={onAccept}>Yes</Button>
<Button onPress={onDecline}>No</Button>
</CardSection>
</View>
</Modal>
);
};
const styles = {
cardSectionStyle: {
justifyContent: 'center'
},
textStyle: {
flex: 1,
fontSize: 18,
textAlign: 'center',
lineHeight: 40
},
containerStyle: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
position: 'relative',
flex: 1,
justifyContent: 'center'
}
};
export default { Confirm };
The error only occurs when I add the confirm component to EmployeeEdit. When I remove the confirm component at the bottom the error goes away. Is there some error in my confirm component?
Thanks
at the bottom of Confirm.js it should be
export { Confirm };
not
export default { Confirm };
When you're importing Confirm using curly braces
import { Card, CardSection, Button, Confirm } from './common';
make sure you're not exporting it using default like what you did:
export default { Confirm };
because once you use
default syntax, it doesn't require curly braces syntax when importing.
You can avoid the flower braces in all.
Do this.
In your Confirm.js
export default Confirm
In your EmployeeEdit.js
import Confirm from './Confirm'
As you see, I have omitted the braces. According to the ES6 Documentation, if a module defines a default export, then you can import the default export without the use of curly braces. Refer here: What is "export default" in javascript?

Categories

Resources