I am trying to create a Profile page where the user can upload an image as the react-native-elements Avatar and update his profile information on a native-base form element.
I am also using the React Native default ImageEditor for image cropping and ImagePicker from Expo to select images.
But when I open the app on Expo, i get this error
Invariant Violation: Invariant Violation: Text strings must be rendered within a component
Below is the code that I am using.
Please help.
import React from "react";
import {
View,
Text,
FlatList,
ActivityIndicator,
TouchableOpacity,
StyleSheet,
ImageEditor
} from "react-native";
import { Avatar } from "react-native-elements";
import { Container, Content, Form, Input, Label, Item } from 'native-base';
import * as Expo from 'expo';
export default class ProfileScreen extends React.Component {
static navigationOptions = {
}
constructor(props) {
super(props);
this.state = {
loading: false,
image: null,
error: null,
refreshing: false
};
}
async _pickImage() {
let result = await Expo.ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (result.cancelled) {
console.log('got here');
return;
}
let resizedUri = await new Promise((resolve, reject) => {
ImageEditor.cropImage(result.uri,
{
offset: { x: 0, y: 0 },
size: { width: result.width, height: result.height },
displaySize: { width: 100, height: 100 },
resizeMode: 'contain',
},
(uri) => resolve(uri),
() => reject(),
);
});
// this gives you a rct-image-store URI or a base64 image tag that
// you can use from ImageStore
this.setState({ image: resizedUri });
}
render () {
let { image } = this.state;
return (
<Container>
<Content>
<View style={{flex:1, flexDirection: 'column', alignContent: 'flex-start', marginLeft: 20}}>
<View style={{flex:1, flexDirection: 'row', alignContent: 'flex-end'}}>
<TouchableOpacity onPress={() => alert('Save')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Save</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('Cancel')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Cancel</Text>
</TouchableOpacity>
</View>
<View style={{height: 30}}></View> //Empty view
<View style={{alignContent: 'center'}}>
<Avatar rounded size="xlarge" title="Profile Photo" source={{ uri: this.state.image }} onPress={this._pickImage}/>
</View>
<View style={{height: 30}}></View> //Empty view
<Form>
<Item floatingLabel>
<Label style={styles.labelText}>First Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Last Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Email</Label>
<Input/>
</Item>
</Form>
</View>
</Content>
</Container>
)
}
}
const styles = StyleSheet.create({
labelText: {
fontSize: 12,
color: '#1f618d',
fontWeight: '100'
}
});
the problem is the way that use comment in render //Empty View use something like that {/* Empty view */}
Comments inside JSX must have the following syntax.
{/* Empty view */}
Remove comment using like //Empty view
if you wish to add comment in render return method you have to use {/*Empty View*/} something like this.
Instead of
<View style={{height: 30}}></View> //Empty view
write
<View style={{height: 30}}>{/*Empty View*/}</View>
you can not add comment directly like //comments in return function, only allow to in render or business logic parts.
Thanks
remove the // comment
make use of jsx commenting style
{/* comment */}
This can happen if you pass and empty string into a component, which is then "rendered" within a <Text> element.
Related
import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
class App extends Component {
constructor(props){
super(props)
this.state={
selected:null
}
}
handle=()=>{
this.setState({selected:1})
}
render() {
return (
<View>
<TouchableOpacity style={[styles.Btn, {backgroundColor:this.state.selected===1?"green":"white"}]} onPress={this.handle}>
<Text style={styles.BtnText}>Button 1</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 2</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 3</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
Btn: {
borderWidth: 1,
width: 100,
height: 20,
borderRadius: 8,
margin: 5,
padding: 10,
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
},
BtnText: {
fontSize: 15,
},
});
export default App;
Snack Link : https://snack.expo.dev/U_fX-6Tao-
I want to make it so when I click a button, the active button backgroundColor should change to "green" and text to "white" and the rest of the buttons backgroundColor and textColor should stay "red". But when I click another button then that button should become active and the previous active button should get back to its normal state.
It would be wonderful if you could also explain the logic behind it as I'm a newbie in React Native.
Thank you.
You are always setting the active button to the first one. Also, I would use an array to render the buttons. I would do something like this:
class App extends Component {
constructor(props){
super(props)
this.state = {
selected: null
}
}
handlePress = (item) => {
this.setState({ selected: item })
}
render() {
return (
<View>
{[...Array(3).keys()].map((item) => {
return (
<TouchableOpacity key={item} style={[styles.Btn, {backgroundColor: this.state.selected === item ? "green" : "white" }]} onPress={() => this.handlePress(item)}>
<Text style={styles.BtnText}>Button {item + 1}</Text>
</TouchableOpacity>
)
})}
</View>
);
}
}
I created an Themed component(OK I did not create it. It is there when I create the app with Expo).
import { useState } from 'react';
import { TouchableOpacity as DefaultTouchableOpacity } from 'react-native';
export type TouchableProps = DefaultTouchableOpacity['props'] & { activeBgColor?: string };
export function TouchableOpacity(props: TouchableProps) {
const [active, setActive] = useState(false);
const { style, activeBgColor, ...otherProps } = props;
if (activeBgColor) {
return (
<DefaultTouchableOpacity
style={[style, active ? { backgroundColor: activeBgColor } : {}]}
activeOpacity={0.8}
onPressIn={() => setActive(true)}
onPressOut={() => setActive(false)}
{...otherProps}
/>
);
}
return <DefaultTouchableOpacity style={style} activeOpacity={0.8} {...otherProps} />;
}
Then I use this TouchableOpacity everywhere.
<TouchableOpacity
style={tw`rounded-sm h-10 px-2 justify-center items-center w-1/5 bg-sky-400`}
activeBgColor={tw.color('bg-sky-600')}
>
<Text style={tw`text-white font-bold`}>a Button</Text>
</TouchableOpacity>
Oh I am writing TailwindCSS with twrnc by the way. You will love it.
See the screenshot below.
i'm new to react native and trying to use flatlist inside another component that's been rendered by another flatlist.
My concern is in the nested flatlist used like this:
Card component
import React, { useContext } from "react"
import { View, Image, Text, StyleSheet, FlatList } from "react-native";
import { QueryContext } from "../context/QueryContext"
function Card(props) {
const [query, setQuery] = useContext(QueryContext)
const { genres_list } = query
const { posterURLs, originalTitle, genres } = props
const listData = []
genres.forEach(genre => {
listData.push({ key: genres_list[genre] })
})
const renderItem = (item) => {
return (
<View>
<Text style={styles.item}>
{item.index}
{item.key}
</Text>
</View>
)
}
return (
<View style={styles.container}>
<Image
style={styles.images}
source={{ uri: posterURLs["original"] }} />
<Text style={styles.title}>{originalTitle}</Text>
<FlatList
data={listData}
renderItem={renderItem}
keyExtractor={(item)=> item.key}
/>
</View>
);
}
const styles = StyleSheet.create({
images: {
width: 400,
height: 500
},
container: {
flex: 1,
backgroundColor: 'lightgrey',
justifyContent: 'center',
alignItems: 'center',
},
title: {
fontSize: 30
},
item: {
padding: 10,
fontSize: 15,
color: "red",
},
})
I have to prepare the data for the flatlist since is inside an object that comes from the context. Weirdly enough i can see the index from item.index but not the item.key which makes me think is some styling issue but as much change i make i'm unable to see it
The card component is rendered by another flatlist and i don't know if that matters or not.
Thanks in advance
Nothing was showing because the data item.key values were actually stored in item.item.key
I am trying to implement copy and paste within my TextInput but cant seem to achieve it. I was expecting a tooltip when I long-pressed on my TextInput, however nothing happens.
I know about Clipboard and would know how to implement it, but I cant seem to get the paste option to pop to the user.
Any ideas how I can achieve this?
<TextInput
maxLength={29}
autoCapitalize={'characters'}
numberOfLines={1}
keyboardType={'default'}
underlineColorAndroid='transparent'
autoCorrect={false}
value={IBAN.printFormat(this.state.ibanInput)}
returnKeyType={'next'}
onChangeText={iban => this.verifyIban(iban)}
style={[{ borderWidth: 1, borderRadius: 2, height: '100%', width: '100%', textAlign: 'center', fontSize: width/24 },
]}
/>
Here is the answer if copy/paste does not work for TextInput - React Native
Step 1) In Contructor take testWidth property and assign value as '99%'.
e.g.
this.state = {testWidth: '99%' };
Step 2) In componentDidMount change testWidth value like '100%', do it inside of setTimeout.
e.g.
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
Step 3) In style attribute of TextInput add dynamic width which we declare in Contractor, e.g
<TextInput style={{ width: this.state.testWidth }} />
Here is the full code: (Just copy and paste in App.js file).
import React, { Component } from 'react';
import { TextInput, View } from 'react-native';
export class App extends Component {
constructor(props) {
super(props);
this.state = { text: '', testWidth: '99%' };
}
componentDidMount() {
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
}
render() {
return (
<View style={{ marginTop: 50 }}>
<TextInput
style={{ width: this.state.testWidth }}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
</View>
);
}
}
Good Luck
Have a look at this code!: https://github.com/facebook/react-native/issues/18926#issuecomment-490541013
<ScrollView
contentContainerStyle={Styles.contentContainerStyle}
keyboardShouldPersistTaps="handled"
removeClippedSubviews={false}>
<KeyboardAvoidingView>
<Text style={Styles.labelPageTitle}>
{'bla bla bla'}
</Text>
<Text>
{'bla bla bla'}
</Text>
<TextInput
onChangeText={text => this.setState({ title: text })}
style={Styles.textInput}
value={title}
/>
</KeyboardAvoidingView>
use RN-clipboard
const text = await Clipboard.getString()
setCopiedText(text)
I am new to react native and have been doing this for a week or so. I just finished the tutorials for making an interactive buttons and work on it. But i am stuck on this. The app is really simple right now, just trying to make a form and add some trigger event using onPress on it.
Below is the portion of my code. I am simply lost for words why its not calling SubmitThisForm() on the onPress event.
Can you guys help me on this.
Thanks a lot.
import React, { Component } from 'react';
import {Container, Content, InputGroup,Button, View, Icon, Card,
CardItem, Text, Body} from 'native-base';
import {Input} from './common';
class LoginForm extends Component {
state = {email: '', password: ''};
SubmitThisForm() {
console.log("Can you see this");
}
render () {
return (
<Container>
<Content>
<Card style={styles.FormContainer}>
<CardItem>
<Body>
<InputGroup borderType="regular">
<Icon name="ios-mail-outline" style={{color:'#384850'}}/>
<Input
placeHolder="example#example.com"
value = {this.state.email}
onChangeText={email=>this.setState( { email })}
/>
</InputGroup>
<InputGroup borderType="regular">
<Icon name="lock" style={{color:'#384850'}}/>
<Input
secureTextEntry= {true}
placeHolder="password"
value = {this.state.password}
onChangeText={password=>this.setState( { password })}
/>
</InputGroup>
</Body>
</CardItem>
</Card>
<View style={styles.SignIn}>
<Button block warning onPress={ () => {this.SubmitThisForm()}}><Text>Sign In</Text></Button>
</View>
<View style={styles.SignUp}>
<Button block info><Text>Sign Up</Text></Button>
</View>
<View style={styles.SignIn}>
<Button block primary><Text>Forgot Password</Text></Button>
</View>
</Content>
</Container>
);
};
}
const styles = {
ErrorTextStyle: {
fontSize: 20,
alignSelf: 'center',
color: 'red'
},
FormContainer:{
marginTop:30,
shadowColor:'#000',
shadowOffset:{width:0,height:2},
shadowOpacity:0.1,
shadowRadius:2,
},
SignIn:{
marginTop:10,
flex:1,
alignSelf:'stretch',
},
SignUp:{
marginTop:40,
flex:1,
alignSelf:'stretch',
}
}
export default LoginForm
The include input component is like this:
import React from 'react';
import {Text, View, TextInput} from 'react-native';
const Input = ({ label,value,onChangeText,placeHolder,secureTextEntry }) => {
const {InputStyle,LabelStyle,ContainerStyle } = styles;
return (
<View style = {ContainerStyle}>
<TextInput
secureTextEntry = {secureTextEntry}
placeholder={placeHolder}
autoCorrect={false}
style = {InputStyle}
value={value}
onChangeText={onChangeText}
/>
</View>
);
};
const styles = {
InputStyle:{
color:'#000',
paddingRight:5,
paddingLeft:5,
fontSize:18,
lineHeight:30,
flex:2,
height:40
},
LabelStyle:{
fontSize:18,
paddingLeft:20,
flex:1,
},
ContainerStyle:{
height:40,
flex:1,
flexDirection:'row',
alignItems:'center'
}
}
export { Input };
You need to either use an Arrow function, or bind() SubmitThisForm to your Component.
You can either declare your method like:
SubmitThisForm = () => {
console.log('Can you see this?')
}
Or, you can bind() your function in the constructor by adding:
constructor() {
super()
this.SubmitThisForm = this.SubmitThisForm.bind(this)
}
If you do not bind this in your custom functions, this will equal undefined. When you use Arrow functions however, this is lexically scoped which means the context of this will be the enclosing context (LoginForm)
Native Base docs only shows how to change background color, text color and font size. But it seems not possible to add icons to tabs.
Is it possible or I will need to fork and implement myself?
Thank you.
With NativeBase 2.0 and above you can add icons to Tabs using TabHeading tags inside heading property.
<Content>
<Tabs>
<Tab heading={<TabHeading><Icon name='settings'/></TabHeading>}>
<Tab heading={<TabHeading><Icon name='home'/></TabHeading>}>
</Tabs>
</Content>
You need to implement yourself. I have implemented this functionality. Please have a look if that would be help you.
Create tabs.js
import React from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,RefreshControl
} from 'react-native';
import IconTabs from 'react-native-vector-icons/Ionicons';
import NavigationBar from 'react-native-navbar';
import { Container, Header, Title, Button,Icon } from 'native-base';
const Tabs = React.createClass({
tabIcons: [],
propTypes: {
goToPage: React.PropTypes.func,
activeTab: React.PropTypes.number,
tabs: React.PropTypes.array,
},
componentDidMount() {
this._listener = this.props.scrollValue.addListener(this.setAnimationValue);
},
setAnimationValue({ value, }) {
this.tabIcons.forEach((icon, i) => {
const progress = (value - i >= 0 && value - i <= 1) ? value - i : 1;
});
},
render() {
return (
<View>
<View style={[styles.tabs, this.props.style, ]}>
{this.props.tabs.map((tab, i,) => {
return <TouchableOpacity key={tab} onPress={() => this.props.goToPage(i)} style={styles.tab}>
<IconTabs
name={tab}
size={20}
color={this.props.activeTab === i ? 'rgb(255,255,255)' : 'rgb(189, 224, 250)'}
ref={(icon) => { this.tabIcons[i] = icon; }}
/>
<Text style={{fontWeight:'bold', fontSize:10, color:this.props.activeTab === i ? 'rgb(255,255,255)' : 'rgb(189, 224, 250)'}}>{`${this.props.name[i]}`}</Text>
</TouchableOpacity>;
})}
</View>
</View>
);
},
});
const styles = StyleSheet.create({
tab: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingBottom: 10,
},
tabs: {
height: 50,
flexDirection: 'row',
paddingTop: 5,
borderWidth: 0,
borderTopWidth: 0,
borderLeftWidth: 0,
borderRightWidth: 0,
backgroundColor: '#2196F3',
},
});
export default Tabs;
And use this component in your view like following.
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
ScrollView,Navigator
} from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import Tabs from './tabs';
export default class LeavesTab extends Component{
constructor(props) {
super(props);
}
_navigate(name) {
this.props.navigator.push({
name: name,
passProps: {
name: name
}
})
}
render() {
let Tabname = ["Tab1","Tab2","Tab3","Tab4"];
return (
<ScrollableTabView
initialPage={this.props.index}
renderTabBar={() => <Tabs name={Tabname} navigator={this.props.navigator} showHeader={true} />}
>
<ScrollView tabLabel="md-calendar">
<Requests tabLabel='Requests' navigator={this.props.navigator} />
</ScrollView>
<ScrollView tabLabel="md-checkbox">
<LeaveList tabLabel='Approved' navigator={this.props.navigator} />
</ScrollView>
<ScrollView tabLabel="md-time">
<LeaveList tabLabel='Pending' navigator={this.props.navigator} />
</ScrollView>
<ScrollView tabLabel="md-close-circle">
<LeaveList tabLabel='Rejected' navigator={this.props.navigator} />
</ScrollView>
</ScrollableTabView>
);
}
}
const styles = StyleSheet.create({
});
Santosh's answer is right, but I found a cleaner way to implement this based on Native Base tabs.
A rendering tab component is necessary, like in Santosh's example.
But in the component, instead of using the ScrollableTabView, I can use React Native's Tabs component. An example:
export default class App extends Component {
render() {
return (
<Container>
<Header>
<Title>Header</Title>
</Header>
<Content>
<Tabs renderTabBar={() => <TabBar />}>
<One tabLabel="video-camera" />
<Two tabLabel="users" />
</Tabs>
</Content>
<Footer>
<FooterTab>
<Button transparent>
<Icon name="ios-call" />
</Button>
</FooterTab>
</Footer>
</Container>
);
}
}
EDIT
#KumarSanketSahu said that version 2.0 is comming with the ability of changing icons in the tabs. My answer above is for version 0.5.x.