How to scroll a page in React Native - reactjs

I can't scroll my page. What is wrong?
export default class CustomersTab extends Component {
constructor(props) {
super(props);
this.state = {
token: "",
isLoading: true,
dataSource: null
};
}
componentWillMount() { MY APİ CODES - HERE İS NOT İMPORTANT
)
.then(response => response.json())
.then(responseData => {
this.setState({
isLoading: false,
dataSource: responseData.result
});
});
})
.catch(error => console.warn(error));
}
static navigationOptions = {
title: "Firmaların Listesi",
tabBarIcon: <Icon name="ios-people" style={{}} />
};
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
} else {
return this.state.dataSource.map((val, key) => {
return (
<List key={key}>
<ListItem
roundAvatar
avatar={{ uri: "url/notimportant" }}
key={key}
title={val.name+" "+val.surname}
subtitle={val.customerType}
/>
</List>
);
});
}
}
}
I tried different codes but it did not improve. How can I view all the data from the page? The "Load others" button may also work. Does anyone have an idea??
Note: DATA is ok. The problem is scroll.

Your render elements should be wrapped withing ScrollView.
return (
<ScrollView>
{this.state.dataSource.map((val, key) => {
return (
<List key={key}>
<ListItem
roundAvatar
avatar={{ uri: "url/notimportant" }}
key={key}
title={val.name + " " + val.surname}
subtitle={val.customerType}
/>
</List>
);
})}
</ScrollView>
);

you can use FlatList and ScrollView. remember to import them. if you see the react-native docs and read it you can use it. another tag that you use it like View don't scroll.

Related

React component not running componentDidmount in my project, so I get error isEdit of undefined?

When I run my react-native component, I get the following error:
However, in the debugger in constructor and componentWillmount and render lifecycle, isEdit is false.
Only componentDidmount is not printing anything, so I think the component is not running componentDidmount lifecycle and I don't know the error reason for this.
constructor(props: IProps) {
// isEdit: false
super(props);
// const {navigation} = this.props;
props.navigation.setOptions({
headerRight: () => {
return <HeaderRightBtn onSubmit={this.onSubmit} />;
},
});
}
componentWillmount() {
// isEdit: false
}
componentDidmount() {
// isEdit of undefined
}
render() {
// isEdit: false
const {categorys, isEdit} = this.props;
const {myCategorys} = this.state;
const classifyGroup = _.groupBy(categorys, (item) => item.classify);
return (
<ScrollView style={styles.container}>
<Text style={styles.classifyName}>我的分类</Text>
<View style={styles.classifyView}>
<DragSortableView
dataSource={myCategorys}
renderItem={this.renderItem}
sortable={isEdit}
fixedItems={fixedItems}
keyExtractor={(item) => item.id}
onDataChange={this.onDataChange}
parentWidth={parentWidth}
childrenWidth={itemWidth}
childrenHeight={itemHeight}
marginChildrenTop={margin}
onClickItem={this.onClick}
/>
{/* {myCategorys.map(this.renderItem)} */}
</View>
<View>
{Object.keys(classifyGroup).map((classify) => {
return (
<View key={classify}>
<Text style={styles.classifyName}>{classify}</Text>
<View style={styles.classifyView}>
{classifyGroup[classify].map((item, index) => {
if (
myCategorys.find(
(selectedItem) => selectedItem.id === item.id,
)
) {
return null;
}
return this.renderUnSelectedItem(item, index);
})}
</View>
</View>
);
})}
</View>
</ScrollView>
);
}
}
Correct names of methods are
“componentDidMount()” and “UNSAFE_componentWillMount()” as per componentdidmount and unsafe_componentwillmount respectively.
Note that componentWillMount() is changed to UNSAFE_componentWillMount() as per the official docs.

Access state in container component

How can I access (get and set) state inside a container component?
I am getting Undefined is not an object evaluating this.state.* because it cannot be accessed from MultiImagePost. Is there a way to bind this to the container component?
export default class ImagePost extends React.Component {
state = {
index: 0,
modalVisible: false,
currentImages: []
};
render() {
const { imageCount } = this.props;
if (imageCount == 1) {
return <SingleImagePost postObject={this.props} />
} else {
return <MultiImagePost postObject={this.props} />
}
}
const MultiImagePost = ({ postObject }) => (
<View>
<FlatList
data={[{key: 'a'}]}
renderItem={({item}) =>
<TouchableOpacity>
<View>
<FlatGrid
itemDimension={100}
items={postObject.images}
renderItem={({ item, index }) => (
<TouchableHighlight
onPress={() => {
this.setState({
modalVisible: true,
index: this.state.index,
currentImages: postObject.images
});
}}>
<Image
source={{ uri: item }}
/>
</TouchableHighlight>
)}
/>
</View>
</TouchableOpacity>
}
/>
</View>
);
}
MultiImagePost is a stateless(functional) component, so it has no state.
U should manage state in ImagePost or consider using React hook.
I can't run your code, if MultiImagePost is inside ImagePost, you may try to see if it works.
I think you have mixed up class component with functional component. You need to change your code a bit like,
export default class ImagePost extends React.Component {
state = {
index: 0,
modalVisible: false,
currentImages: []
};
render() {
const { imageCount } = this.props;
if (imageCount == 1) {
return <SingleImagePost postObject={this.props} />
} else {
return <>{this.MultiImagePost(this.props)}</> //Instead of component make it as function call
}
}
//Make this as instance function
MultiImagePost = (postObject) => (
<View>
<FlatList
data={[{key: 'a'}]}
renderItem={({item}) =>
<TouchableOpacity>
<View>
<FlatGrid
itemDimension={100}
items={postObject.images}
renderItem={({ item, index }) => (
<TouchableHighlight
onPress={() => {
this.setState({
modalVisible: true,
index: this.state.index,
currentImages: postObject.images
});
}}>
<Image source={{ uri: item }} />
</TouchableHighlight>
)}
/>
</View>
</TouchableOpacity>
}
/>
</View>
);
}

View only rendering when not refering to array

It seems that i miss something during my first react native project:
The render function is not rendering the view when i try to display an array which is assigned to state.
i can only console log the array (in the setState callback) while also render the view when i comment out the part where i refer to the array.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
array: [],
token: '',
}
}
setLoading = () => {
this.setState({ loading: true }, () => this.login())
}
login = async () => {
try {
const response = await
fetch(`http://10.0.2.2`);
const res = await response.json();
this.setState({
name: res.name,
address: res.address,
token: res.token,
}, function () {
this.setState({
array: res.array,
loading: false
}, function () {
//only reaching when commented out the array-part in the render
//function
console.log(this.state.array[0].grade)
});
})
}
catch{
console.log('in CATCH ERROR')
} }
render() {
if (this.state.loading) {
return (
<View>
<ActivityIndicator />
</View>
);
}
return this.state.token ? (
<View >
<Text> {this.state.name}</Text>
//this works !
<Text> {this.state.array[0].prof}</Text>
//only rendering without the mapping of the array
{/*this.state.array.map((item, i) => (
<div key={i}>
<Text >Grade : {item.grade}</Text>
<Text >Class : {item.class}</Text>
<Text >Proffessor : {item.prof}</Text>
</div>
))*/}
</View>
) : (
<View>
<TextInput
value={this.state.username}
onChangeText={(username) => this.setState({ username })}
placeholder={'Username'}
/>
<TextInput
value={this.state.password}
onChangeText={(password) => this.setState({ password })}
placeholder={'Password'}
secureTextEntry={true}
/>
<Button
title={'Login'}
style={styles.input}
onPress={this.login.bind(this)}
/>
</View>
)
};
according to the docs this should be possible.. any Pro here that has an idea why this is happening?

How to setState more than one object and pass to other component?

I'm new at react-native. I try a lot of ways to get arrays of JSON data from openweathermap's API but didn't work. I want some suggestions and guidelines.
I just fetch JSON data and want to set state more than one object from JSON data.
Example of JSON data. I want to get temp, humidity, description and icon from 2 arrays in list[].
"list":[
{
"dt":1541440800,
"main":{
"temp":25.85,
"temp_min":25.85,
"temp_max":27.35,
"pressure":1022.17,
"sea_level":1023.04,
"grnd_level":1022.17,
"humidity":100,
"temp_kf":-1.5
},
"weather":[
{
"id":500,
"main":"Rain",
"description":"light rain",
"icon":"10n"
}
],
"dt_txt":"2018-11-05 18:00:00"
},
{
"dt":1541451600,
"main":{
"temp":26.38,
"temp_min":26.38,
"temp_max":27.5,
"pressure":1021.34,
"sea_level":1022.24,
"grnd_level":1021.34,
"humidity":100,
"temp_kf":-1.12
},
"weather":[
{
"id":802,
"main":"Clouds",
"description":"scattered clouds",
"icon":"03n"
}
],
"dt_txt":"2018-11-05 21:00:00"
}
Here is my JSON fetching component. I want to show different data from arrays by passing state to front-end component.
export default class Forecast extends Component {
constructor(props) {
super(props);
this.state = {
hourlyForecast: {}
};
}
fetchData = () => {
fetch(
`http://api.openweathermap.org/data/2.5/forecast?q=${
this.props.currentCity
}&units=metric&appid=${API_KEY}`
)
.then(response => response.json())
.then(json => {
this.setState({
hourlyForecast: {
temp: json.list[0].main.temp,
humidity: json.list[0].main.humidity,
icon: json.list[0].weather[0].icon,
description: json.list[0].weather[0].description,
date_time: json.list[0].dt_txt
}
});
})
.catch(error => {
console.warn(error);
});
};
componentDidMount = () => this.fetchData();
render() {
return (
<Container>
<Content>
<ForecastCards {...this.state.hourlyForecast} />
<ForecastCards {...this.state.hourlyForecast} />
</Content>
</Container>
);
}
}
And here is my front-end component.
export default class ForecastCards extends Component {
render() {
return (
<Card>
<CardItem>
<Body>
<View style={{flex: 1, flexDirection: "row"}}>
<View>
<Text>{this.props.date_time}</Text>
<Text>Temperature: {this.props.temp} °C</Text>
<Text>Humidity: {this.props.humidity} %</Text>
</View>
<View style={{marginLeft: 100}}>
<Image
style={{ width: 60, height: 60 }}
source={{
uri: `http://openweathermap.org/img/w/${
this.props.icon
}.png`
}}
/>
<Text>{this.props.description}</Text>
</View>
</View>
</Body>
</CardItem>
</Card>
);
}
}
Here you go with a solution
fetchData = () => {
fetch(
`http://api.openweathermap.org/data/2.5/forecast?q=${this.props.currentCity}&units=metric&appid=${API_KEY}`
)
.then(response => response.json())
.then(json => {
this.setState({
hourlyForecast: {
temp: json.list[0].main.temp,
humidity: json.list[0].main.humidity,
icon: json.list[0].weather[0].icon,
description: json.list[0].weather[0].description,
date_time: json.list[0].dt_txt
}
});
})
.catch(error => {
console.warn(error);
});
};
componentDidMount = () => this.fetchData();
render() {
return (
<Container>
<Content>
<ForecastCards hourlyForecast={this.state.hourlyForecast} />
<ForecastCards hourlyForecast={this.state.hourlyForecast} />
</Content>
</Container>
);
}
And here is my front-end component.
export default class ForecastCards extends Component {
render() {
return (
<Card>
<CardItem>
<Body>
<View style={{flex: 1, flexDirection: "row"}}>
<View>
<Text>{this.props.hourlyForecast.date_time}</Text>
<Text>Temperature: {this.props.hourlyForecast.temp} °C</Text>
<Text>Humidity: {this.props.hourlyForecast.humidity} %</Text>
</View>
<View style={{marginLeft: 100}}>
<Image
style={{ width: 60, height: 60 }}
source={{
uri: `http://openweathermap.org/img/w/${
this.props.hourlyForecast.icon
}.png`
}}
/>
<Text>{this.props.hourlyForecast.description}</Text>
</View>
</View>
</Body>
</CardItem>
</Card>
);
}
}
ForecastCards.propTypes = {
hourlyForecast: PropTypes.object
}
Setting the state is fine. For passing the props <ForecastCards hourlyForecast={this.state.hourlyForecast} />
Provide the PropType in ForecastCards component using ForecastCards.propTypes = {
hourlyForecast: PropTypes.object
}
For access date_time or any other key, please use this.props.hourlyForecast.date_time or this.props.hourlyForecast.{key}
Hope this will help you.

Slow image load/Pull images from storage - firebase - react native

I am pulling data from my firestore DB, one of the fields on each DB item is image, the value of each being a URL to an image with my firebase storage.
What I'd like to do is pull the image directly from storage as part of the loop that pulls from firestore.
I am trying to do this as when this loop renders the items, the images are taking a few seconds to appear on the screen.
Please advise if there is an alternative to solve this issue?
FirebaseData.js
onCollectionUpdate = (querySnapshot) => {
const data = [];
querySnapshot.forEach((doc) => {
const { title, image, url, description } = doc.data();
data.push({
key: doc.id,
doc, // DocumentSnapshot
title,
image,
description,
url
});
});
this.setState({
data,
loading: false
});
}
render() {
if (this.state.loading) {
return <Spinner />; //RETURN A LOADING ICON
}
return (
<List containerStyle={styles.listStyle}>
<FlatList
data={this.state.data}
renderItem={({ item }) => <ChildList {...item} />}
/>
</List>
);
}
}
ChildList.js
export default class ChildListRow2 extends React.PureComponent {
render() {
return (
<ListItem
title={
<View>
<Image source={{ uri: this.props.image }} style={styles.imageStyle} />
<Text style={styles.titleTextStyle}>{this.props.title}</Text>
</View>
}
subtitle={
<View>
<Text style={styles.subTitleTextStyle}>{this.props.description}</Text>
</View>
}
hideChevron
onPress={() => Linking.openURL(this.props.url)}
containerStyle={styles.listItemStyle}
/>
);
}
}
You can use onLoadEnd and onLoadStart properties of Image component to show and hide the rest of the data. You can show a loading spinner till the file loads and then show the complete component when it finishes.
Example
export default class ChildListRow2 extends React.PureComponent {
constructor() {
super();
this.state = {
loaded: false
};
}
imageLoaded = () => {
this.setState({ loaded: true })
}
render() {
return (
<ListItem
title={
<View>
<Image
source={{ uri: this.props.image }}
style={styles.imageStyle}
onLoadEnd={this.imageLoaded}
/>
<Text style={styles.titleTextStyle}>{this.props.title}</Text>
</View>
}
subtitle={
<View>
<Text style={styles.subTitleTextStyle}>{this.props.description}</Text>
</View>
}
hideChevron={this.state.loaded}
onPress={() => Linking.openURL(this.props.url)}
containerStyle={styles.listItemStyle}
/>
);
}
}

Resources