I've just started with React Native and I'm sure I'm missing something small. However, for the life of me I can't figure out how to display this.data.mission.XX anywhere. I can console log the data and see it in Xcode, but that's it.
var React = require('react-native');
var Parse = require('parse/react-native');
var ParseReact = require('parse-react/react-native');
var {
Component,
StyleSheet,
Image,
Text,
View,
StatusBarIOS,
} = React;
var CountdownClock = require('./CountdownClock');
var CountdownScreen = React.createClass({
mixins: [ParseReact.Mixin],
getInitialState: function() {
return{
mission: null,
};
},
componentDidMount: function() {
StatusBarIOS.setStyle('light-content');
},
observe: function() {
return {
mission: (new Parse.Query('mission')).equalTo('featuredMission', true)
};
},
render: function() {
console.log(this.data.mission);
return (
<Image source={{uri: '#'}} style={styles.backgroundImage}>
<View style={styles.mainContainer}>
<View style={styles.clock}>
<CountdownClock />
</View>
<View style={styles.featured}>
<Text style={styles.header}> Name: {this.data.mission.missionName} </Text>
<Text style={styles.header}> Estimated Start: {this.data.mission.windowStart}</Text>
<Text style={styles.header}> Site: {this.data.mission.missionSite}</Text>
<Text style={styles.header}> Vehicle: {this.data.mission.missionVehicle}</Text>
<Text style={styles.description}>{this.data.mission.missionDescription}</Text>
</View>
</View>
</Image>
);
}
});
Taking into account that this.data is logging out, you probably need to do something like this:
Set the data property in the state:
getInitialState(){
data: {}
}
Attach this.data to the state:
componentWillUpdate() {
this.setState({
data: this.data
})
}
Use this.state.data vs this.data
<View style={styles.featured}>
<Text style={styles.header}> Name: {this.state.data.mission.missionName} </Text>
<Text style={styles.header}> Estimated Start: {this.state.data.mission.windowStart}</Text>
<Text style={styles.header}> Site: {this.state.data.mission.missionSite}</Text>
<Text style={styles.header}> Vehicle: {this.state.data.mission.missionVehicle}</Text>
<Text style={styles.description}>{this.state.data.mission.missionDescription}</Text>
</View>
Related
A react native 0.70 component displays items in FlatList. The array items is a state and is assigned value in hook useEffect. I would like to jest (0.29) it to see if a item's name is shown up on screen so a mock of state items is needed. Here is the render item code for FlatList:
return (
<TouchableOpacity testID={'listselltrade.detail'} onPress={() => {item.sell ? navigation.navigate("Deal Detail", {item:item}) : navigation.navigate("Trade Detail", item={item})} } >. <<== here is the testID
<View style={{flex:1, flexDirection:"row", alignItems:"center", width:wp("100%"), height:wp("17%")}}>
<View style={{width:wp("17%"), padding:wp("0.1%")}}>
{sourceUri && sourceAltUri ? <CachedImage source={{uri:sourceUri}} sourceAlt={{uri:sourceAltUri}} style={styles.itemImage} /> : null}
</View>
<View style={{width:wp("25%")}}>
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>{item.artwork.item_name}</Text>
</View>
<View style={{width:wp("8%")}}>
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>{helper.returnStatus(item.status)}</Text>
</View>
<View style={{width:wp("7%")}}>
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>{item.price+item.shipping_cost}</Text>
</View>
<View style={{width:wp("3%"),flexDirection:"row"}}>
{item.sell ? <Icon name='logo-usd' size={_size} /> : <Icon name='sync' size={_size} />}
</View>
<View style={{width:wp("8%")}}>
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>
{item.artwork.category.category_name}
</Text>
</View>
{item.sell && _me.id !== data.uploader_id && <View style={{width:wp("15%")}}>
<TouchableOpacity onPress={() => {navigation.push('ListBuyExg', {uploader_id:item.artwork.uploader_id, title:_sellerposter_name})} }>
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>
{_sellerposter_name}
</Text>
</TouchableOpacity>
</View> }
{!item.sell && _me.id !== data.uploader_id && <View style={{width:wp("15%")}}>
<TouchableOpacity onPress={() => {navigation.push('ListBuyExg', {uploader_id:item.artwork.uploader_id, title:_sellerposter_name})} } >
<Text style={{fontSize:wp("4.2%"), flexWrap:"wrap"}}>
{_sellerposter_name}
</Text>
</TouchableOpacity>
</View> }
<View style={{width:wp("20%")}}>
<Text style={{fontSize:wp("3%"), flexWrap:"wrap"}}>{item.active_date.substring(0,10)}</Text>
</View>
</View>
</TouchableOpacity>
);
Here is jest code:
test ('has screen detail', async () => {
const route = {params: {title:"my title", uploader_id:8}}; //8 is a test user. all is listed
const navigation = {navigate:jest.fn()};
const propsVal = {device_id:"a device id"};
const authVal = {result:"fdkfjdsl;fjdsafkl", myself:{id:1,name:"me"}};
const stateVal = {name:"me", alias:"akkus", aka:"aka"};
const items = [{artwork:{item_name:"work name"}}]; //<<==mock state items
const component = (
<NavigationContainer>
<propsContext.Provider value={propsVal}>
<authContext.Provider value={authVal}>
<stateContext.Provider value={stateVal}>
<ListSellTrade route={route} navigation={navigation}/>
</stateContext.Provider>
</authContext.Provider>
</propsContext.Provider>
</NavigationContainer>);
const wrapper = render(component);
expect(screen.getByText('my title')).toBeTruthy(); //<<==pass
expect(screen.getByText('work name')).toBeTruthy(); //<<==failed
expect(screen.getByTestId('listselltrade.detail')).toBeTruthy(); //<<==failed
})
But there is no item was rendered on screen and 2 expects were failed. What is the right way to mock state items so it can be fed into the jest for further test?
You should start by using screen.debug() to output the host element tree your component is rendering. This should help you understand what actually gets rendered in your RNTL tests.
You might also want to consult official RNTL + React Navigation example how to properly test screen components when using React Navigation.
I am trying to add a different image to each key of my flatlist. However, the images aren't being showed on the screen by rendering the items, just the keys. The source of the images is correct, so as the name of the images. Can you find the mistake that I have made?
export default class HomeScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
searchText: '',
};
}
render() {
//Data can be coming from props or any other source as well
const data = [
{
key: 'Athlean-X',
logo: 'athlean_x.png'
},
{
key: 'Panelaria Ricardo Faria',
logo: "euro2020.png"
},
{
key: 'tEsLa',
logo: "jamor.png"
},
{
key: 'Lols Inc.',
logo: "rock_in_rio.png"
},
{
key: 'Vale de Silicone',
logo: 'splash.png'
},
{
key: 'Empresa do Helder',
logo: "edp_cooljazz.png"
},
{
key: 'BD Swiss',
logo: "superbock_superrock.png"
}
];
const filteredData = this.state.searchText
? data.filter(x =>
x.key.toLowerCase().includes(this.state.searchText.toLowerCase())
)
: data;
return (
<View style={styles.container}>
<View style={styles.flatlist}>
<FlatList
data={filteredData}
renderItem={({ item }) => (
<View style={{flexDirection:'row'}}>
<Image
style={{width:50, height:50, alignSelf: 'center', borderRadius:300}}
source={{uri:item.logo}}
/>
<Text style={styles.item}>{item.key}</Text>
</View>
)}
/>
</View>
</View>
);
}
}
The images saved locally must be called using require function.
<FlatList
data={filteredData}
renderItem={({ item }) => (
<View style={{flexDirection:'row'}}>
<Image
style={{width:50, height:50, alignSelf: 'center', borderRadius:300}}
source={require(item.logo)}
/>
<Text style={styles.item}>{item.key}</Text>
</View>
)}
keyExtractor={item=>item.key}
/>
Flatlist requires every individual component in the list to have a unique key. That's why item.key is provided to key extractor.
I have a list of items, each having a body and a source. Currently it renders like this:
const ListItem = (props) => {
const {body, source} = props.context;
return (
<View style={styles.item}>>
<View style={{backgroundColor: 'lightblue'}}>
<Text style={styles.body}>{body}</Text>
</View>
<View style={{backgroundColor: 'lightyellow'}}>
<Text style={styles.source}>{source}</Text>
</View>
</View>
);
}
That's a lot of nesting and containers. Could it be done more optimally?
I am going to post my comment as an answer.
Previous comment:
I guess it depends on your design, AFAIK this is fine within React Native assuming you're using an optimized way of rendering your list (e.g. using a FlatList or similar)
As per your following comment, I don't think it's monstrous at all.
Here's an alternative. However, for readability I would much prefer the snippet you posted in your question.
const ListItem = props => {
const items = [
{ key: 'body', backgroundColor: 'lightblue' },
{ key: 'source', backgroundColor: 'lightyellow' }
];
return (
<View style={styles.item}>
{
items.map(({ key, backgroundColor }) =>
<View style={{ backgroundColor }}>
<Text style={styles[key]}>
{ props[key] }
</Text>
</View>
)
}
</View>
)
}
The Text component does take backgroundColor so you can let go of the two Views:
<View style={styles.item}>
<Text style={[styles.body, {backgroundColor: '...'}]}>{body}</Text>
<Text style={[styles.source, {backgroundColor: '...'}]}>{source}</Text>
</View>
Additionally, I don't know what the styles.item consists of, but if you want to go all the way, you might replace the other container View with React.Fragment.
The value set in asyncstorage is null and also the log for usertext is { [TypeError: undefined is not an object (evaluating 'this.state.usertext')] line: 30, column: 34 }
what might be the problem here?
'use strict'
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Navigator,
Text,
TextInput,
Button,
AsyncStorage,
View
} from 'react-native';
import { Actions } from 'react-native-router-flux';
import api from './utilities/api';
export default class LoginScreen extends Component{
constructor(props) {
super(props);
this.state = { usertext: 'placeholder' , passwordtext: 'placeholder' ,buttonvalue: '
Login'};
}
async login() {
const res = await api.getLoginResult();
const status= res.status;
console.log('log'+status);
if(status==='success'){
try {
console.log('usertext'+this.state.usertext);
await AsyncStorage.setItem('username', this.state.usertext);
var username = await AsyncStorage.getItem('username');
console.log('username'+username);
await AsyncStorage.setItem('password', this.state.passwordtext);
} catch (error) {
// Error saving data
console.log(error);
}
Actions.HomeScreen();
}
}
render() {
return (
<View style={styles.container}>
<View style={styles.containerLogin}>
<View style={styles.headerContainer}>
<Text style={styles.welcome}>PLEASE LOGIN</Text>
</View>
<View style={styles.inputlayouts}>
<TextInput
onChangeText={(usertext) => this.setState({usertext})}
value={this.state.usertext}
/>
<TextInput
onChangeText={(passwordtext) => this.setState({passwordtext})}
value={this.state.passwordtext}
/>
</View>
<View style={styles.buttonView}>
<Button
style={styles.buttonstyle}
onPress={this.login}
title={this.state.buttonvalue}
color="#FF7323">
</Button>
</View>
</View>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'stretch',
backgroundColor: '#1AB591',
},
headerContainer:{
backgroundColor:'#FF7323'
},
buttonView:{
marginLeft:15,
marginRight:15,
marginBottom:15
},
inputlayouts:{
marginLeft:6,
marginRight:6,
marginBottom:10,
},
containerLogin: {
justifyContent: 'center',
alignItems: 'stretch',
backgroundColor: '#FFF',
marginLeft:20,
marginRight:20
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
color:'#FFF'
},
buttonstyle: {
width:20,
}
});
Change
<Button
style={styles.buttonstyle}
onPress={this.login}
title={this.state.buttonvalue}
color="#FF7323">
</Button>
to
<Button
style={styles.buttonstyle}
onPress={this.login.bind(this)}
title={this.state.buttonvalue}
color="#FF7323">
</Button>
When you do onPress={this.login}, the method reference to this will be different than your component. Binding this to method, allows you to reference your this in the function.
we are currently running React-Native 0.33
We are trying to use the refs to go from 1 text input to another when they hit the next button. Classic username to password.
Anyone have any idea? Below is the code we are using. From other posts I've found on stack this is what they've done; however, it's telling us that this.refs is undefined.
UPDATE
So I've narrowed the problem down to
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
If I just render the code below in the renderScene function inside of the original render it works, however with the navigator it won't work. Does anyone know why? Or how to have the navigator show as well as render the code in renderScene to appear in the original render?
class LoginIOS extends Component{
constructor(props) {
super(props);
this.state={
username: '',
password: '',
myKey: '',
};
}
render() {
return (
<Navigator
renderScene={this.renderScene.bind(this)}
navigator={this.props.navigator}
navigationBar={
<Navigator.NavigationBar style={{backgroundColor: 'transparent'}}
routeMapper={NavigationBarRouteMapper} />
} />
);
}
renderScene() {
return (
<View style={styles.credentialContainer}>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="person" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "FirstInput"
style={styles.input}
placeholder="Username"
autoCorrect={false}
autoCapitalize="none"
returnKeyType="next"
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({username: text})}
value={this.state.username}
onSubmitEditing={(event) => {
this.refs.SecondInput.focus();
}}
>
</TextInput>
</View>
</View>
<View style={styles.inputContainer}>
<Icon style={styles.inputPassword} name="lock" size={28} color="#FFCD00" />
<View style={{flexDirection: 'row', flex: 1, marginLeft: 2, marginRight: 2, borderBottomColor: '#e0e0e0', borderBottomWidth: 2}}>
<TextInput
ref = "SecondInput"
style={styles.input}
placeholder="Password"
autoCorrect={false}
secureTextEntry={true}
placeholderTextColor="#e0e0e0"
onChangeText={(text) => this.setState({password: text})}
value={this.state.password}
returnKeyType="done"
onSubmitEditing={(event)=> {
this.login();
}}
focus={this.state.focusPassword}
>
</TextInput>
</View>
</View>
</View>
);
}
Try setting the reference using a function. Like this:
<TextInput ref={(ref) => { this.FirstInput = ref; }} />
Then you can access to the reference with this.FirstInput instead of this.refs.FirstInput
For a functional component using the useRef hook. You can use achieve this easily, with...
import React, { useRef } from 'react';
import { TextInput, } from 'react-native';
function MyTextInput(){
const textInputRef = useRef<TextInput>(null);;
return (
<TextInput ref={textInputRef} />
)
}
Try changing the Navigator's renderScene callback to the following (based on Navigator documentation) cause you will need the navigator object later.
renderScene={(route, navigator) => this.renderScene(route, navigator)}
Then, use 'navigator' instead of 'this' to get the refs.
navigator.refs.SecondInput.focus()