React Native - IOS - Text strings must be rendered within a <Text> component - ios

Looking at my code for few hours, I was not able to understand the root cause for this exception
Error: Text strings must be rendered within a <Text> component.
This error is located at:
in RCTView (created by View)
in View (created by Card)
in Card (created by StartGameScreen
Can anyone give me a hint? Where do I have to check analyzing? I have a Card component indeed. Is this the first place to check according to the error message?
Card
import {View, StyleSheet} from 'react-native'
import Colors from '../../constants/colors'
function Card({children}) {
return (
<View style = {styles.card}> {children} </View>
)
}
export default Card;
StartGameScreen
function StartGameScreen({onPickNumber}) {
const [enteredNumber, setEnteredNumber] = useState('')
function numberInputHandler(enteredText) {
setEnteredNumber(enteredText)
}
function resetInputHandler() {
setEnteredNumber('')
}
function confirmInputHandler() {
const choseNumber = parseInt(enteredNumber)
if (isNaN(choseNumber) || choseNumber <= 0 || choseNumber > 99) {
Alert.alert('Invalid number', 'Number has to be a number between 1 and 99', [{text:'Okay', style:'destructive', onPress:resetInputHandler}]);
return;
}
onPickNumber(choseNumber);
}
return (
<View style={styles.rootContainer}>
<Title>Guess my number</Title>
<Card>
<InstructionText>dsd</InstructionText>
<View style={styles.textInputContainer}>
<TextInput style={styles.numberInput} maxLength={2} keyboardType="number-pad" autoCapitalize='none' onChangeText={numberInputHandler} value={enteredNumber}/>
</View>
<View style = {styles.buttonsContainer}>
<View style={styles.buttonContainer}>
<PrimaryButton onPress={resetInputHandler}>Reset</PrimaryButton>
</View>
<View style={styles.buttonContainer}>
<PrimaryButton onPress={confirmInputHandler}>Confirm</PrimaryButton>
</View>
</View>
</Card>
</View>
)
}
InstructionText
function InstructionText({children}) {
return (
<Text style={styles.instructionText}>{children}</Text>
)
}

const InstructionText = ({children}) => {
return (
<Text style={styles.instructionText}>{children}</Text>
)
}
This should work !!
if you have spaces in your return statement, you have to wrapping it in parenthesis () and using one line per each tag.

Related

React Native Swipeable (Swipe to delete) not closing

I'm using Swipeable from React-Native-Gesture-Handler to incorporate swipe to delete on my page.
When I press delete, the contact gets deleted however the swipeable remains open.
I want it to close after it gets pressed but I can't seem to figure out how to do it.
This is my code:
const RightActions = (progress, dragX) => {
return (
<TouchableOpacity onPress={()=>{DeleteContact(i)}}>
<View style={[ContactsStyles.rightAction]}>
<Text style={ContactsStyles.actionText}>Delete</Text>
</View>
</TouchableOpacity>
)
}
Here is where I have Swipeable:
<Swipeable renderRightActions={RightActions} >
<View style={ContactsStyles.UserContainer}>
<Text numberOfLines={1} style={[Fonts.Name]}> {obj.firstname} {obj.lastname} </Text>
{/* Message/Call Container */}
<View style={ContactsStyles.ImageCont}>
{/* Message */}
<TouchableOpacity onPress={() => Communications.text(obj.phone, 'Hey ' + obj.firstname + ', im in need of a Ryde. Are you able to pick me up? This is my current location: ' + location)} >
<View style={ContactsStyles.ImageBox}>
<Image style={ContactsStyles.Image} source={require('../../assets/icons/message.png')} />
</View>
</TouchableOpacity>
{/* Call */}
<TouchableOpacity onPress = {() => Communications.phonecall( obj.phone , true)}>
<View style={ContactsStyles.ImageBox}>
<Image style={ContactsStyles.Image} source={require('../../assets/icons/phone.png')} />
</View>
</TouchableOpacity>
</View>
{/* End of Message/Call Container */}
</View>
</Swipeable>
You need to use a reference which has a close method on it.
First define a ref
const swipeableRef = useRef(null);
then assign it to Swipeable
<Swipeable
ref={swipeableRef}
renderLeftActions={renderLeftActions}
onSwipeableLeftOpen={() => handleComplete(item)}
>
...
</Swipeable>
and then just call the close method
const closeSwipeable = () => {
swipeableRef.current.close();
}
Note, for multiple Swipeables you should have multiple refs.
let row: Array<any> = [];
let prevOpenedRow;
renderItem ({ item, index }) {
return (
<Swipeable
ref={ref => row[index] = ref}
friction={2}
leftThreshold={80}
rightThreshold={40}
renderRightActions={renderRightActions}
containerStyle={style.swipeRowStyle}
onSwipeableOpen={closeRow(index)}
...
>
...
</Swipeable>);
}
closeRow(index) {
if (prevOpenedRow && prevOpenedRow !== row[index]) {
prevOpenedRow.close();
}
prevOpenedRow = row[index];
}
It's an index issue . When we have our list keyed on index, and we remove one item (eg index=3), the next item (previously index=4) now adopts the earlier index. Swipeable gets confused by this.
The answer is to key the list on something other than index (eg a unique id).
I had the same problem. What I did to solve that was to set the state array (which is shown in a list) to [] first before deleting that particular item. It cleared-up the screen (including the action panel) and rendered new items.
A part of my code:
const [notes, setNotes] = useState([]);
<FlatList
data={notes}
......
when a note was deleted, I did: setNotes([]) and then setNotes(newNotes)

React Native Element Type is invalid Error While using ActivityIndicatorIOS

I have begun to develop a book-searching application using React and Google Books API. However, I have run into an error where my simulator reads:
Element Type is invalid: expected a string (for built-in components) or
a class/function (for composite components) but got: undefined. Check
the render method of 'BookList'.
Given that I am fairly new to React, I was hoping someone might be able to point out the error(s) in my code below. I have noted the place where I think there may be an error. Thanks!
class BookList extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(REQUEST_URL[0])
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.items),
isLoading: false
});
})
.done();
}
render() {
if (this.state.isLoading) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderBook.bind(this)}
style={styles.listView}
/>
);
}
// *** adding this function (and using it) began to cause issues ****
renderLoadingView() {
return (
<View style={styles.loading}>
<ActivityIndicatorIOS
size='large'/>
<Text>
Loading books...
</Text>
</View>
);
}
renderBook(book) {
return (
<TouchableHighlight>
<View>
<View style={styles.container}>
<Image
source={{uri: book.volumeInfo.imageLinks.thumbnail}}
style={styles.thumbnail} />
<View style={styles.rightContainer}>
<Text style={styles.title}>{book.volumeInfo.title}</Text>
<Text style={styles.author}>{book.volumeInfo.authors}</Text>
<Text style={styles.price}>{'Lowest Available Price: ' + book.volumeInfo.price}</Text>
</View>
</View>
<View style={styles.separator} />
</View>
</TouchableHighlight>
);
}
}
var REQUEST_URL = ['https://www.googleapis.com/books/v1/volumes?q=subject:fiction'];
ActivityIndicatorIOS is depreciated use ActivityIndicator instead.

How did I use the push() function in NavigatorIOS?

I want to Push to a new Component by the function push() in NavigatorIOS. It's like following:
renderRow(rowData, sectionID, rowID) {
var imgSource = IMAGE_URLS[rowID];
return (
<TouchableHighlight onPress = {() => {
this.props.navigator.push({
title: 'test',
component: example,
});
}}>
<View>
<View style={styles.row}>
<Image
source={imgSource}
style={styles.thum}
/>
<Text style={styles.text}>
{rowData}
</Text>
</View>
</View>
</TouchableHighlight>
);
}
But it will get a error when I click the TouchableHighlight.
I refered these two questions(1 and 2) before this. And the complete code is in this link
this is not binded to the class inside of renderRow().
You have to bind this either in the constructor:
this.renderRow = this.renderRow.bind(this);
or inside the render method:
render() {
var navStatusBarConfig = {
style: 'light-content',
}
return (
<View style={{ flex: 1, backgroundColor: '#F5FCFF'}}>
<View styles={styles.nav}></View>
<ListView
automaticallyAdjustContentInsets={false}
contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
pageSize={4}
renderRow={this.renderRow.bind(this)}
/>
</View>
);
}
}
As to why, here is the reason :
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding
And a more complete blog about how to bind this [there are many, blogs and ways to bind this]) :
http://blog.andrewray.me/react-es6-autobinding-and-createclass/

How add tabs in react-native IOS using rn-viewpager

I am using rn-viewpager for tabs in react-native. But I am having issues in opening new page on each tab selected.
I am using following link: react-native-viewpager
export default class ViewPagerPage extends Component {
render() {
return (
<View style={{flex:1}}>
<IndicatorViewPager
indicatorPosition="top"
style={{flex:1, paddingTop:20, backgroundColor:'white'}}
indicator={this._renderTitleIndicator()}
>
<View style={{backgroundColor:'cadetblue'}}>
<Text>page one</Text>
</View>
<View style={{backgroundColor:'cornflowerblue'}}>
<Text>page two</Text>
</View>
<View style={{backgroundColor:'#1AA094'}}>
<Text>page three</Text>
</View>
</IndicatorViewPager>
</View>
);
}
_renderTitleIndicator() {
return <PagerTitleIndicator titles={['Page1', 'Page2', 'Page3']} />;
}
return (
<PagerTabIndicator
tabs={tabs}
textStyle={{color:'#999'}}
selectedTextStyle={{color:'#111'}}
iconStyle={{width:25, height:25, tintColor:'#999'}}
selectedIconStyle={{width:25, height:25, tintColor:'#111'}}
/>
);
}
}
I want to open page.js file on click of every tab.

React-native: Why rendering an empty view component creates an error while a text component runs?

I am trying to create an array of View components in react-native that are passed to a parent component. The code below does not work, however if i use Text instead of View it works. I want use view to show empty or filled circles. I couldn't find the reason for it and i assume it should be possible to use an empty view. What am i doing wrong?
class card extends React.Component {
renderScore(balance, fulfill, markImage){
var scores = [];
for (i = 1; i <= fulfill; i++) {
if(i<=balance){
if (markImage) {
scores.push(<View style={styles.emptyCircle} key={i}> </View>);
//scores.push(<View style={styles.emptyCircle} key={i}> <Image source={{uri: markImage}} style={styles.markImage}/> </View>);
}
else{
scores.push(<View style={styles.emptyCircle} key={i}> <View style={styles.punchCircle}></View> </View>);
}
}
else
{
scores.push(<View style={styles.emptyCircle} key={i}> </View>);
}
}
return(scores);
}
}
This will give 'RawText " " must be wrapped in an explicit component.'
However if use
scores.push(<Text style={styles.emptyCircle} key={i}> </Text>);
it works.
It is called from a ListView as
_renderCard(item){
var cardBottom = new cardRenderer();
var childView = cardBottom.renderScore(item.balance, item.fulfill, item.markImage);
console.log(childView);
return(
<View style={styles.mainConatiner}>
<View style={styles.leftConatiner}>
<Image
source={{uri: item.avatarLeft}}
style={styles.thumbnail}
/>
</View>
<View style={styles.rightConatiner}>
<View style={styles.rightUpConatiner}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.title}>{item.subTitle}</Text>
<Text style={styles.title}>{item.expires}</Text>
</View>
<View style={styles.rightDownConatiner}>{childView}</View>
</View>
</View>
);
}
Use below for empty view
return(<></>)
try this
return(<View>{scores}</View>);

Resources