I'm new to programming and react-native and I'm trying to make a Scrollview and get values from a JSON file and show 2 boxes in each row but when I use flexDirection : 'row' they all merge into each other.
Thank you I appreciate every help.
The section below is my code:
export default class Creative extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, refreshing: false, }
}
_fetchData = () => {
const key = 'D0BEFCE031A955294DE1DD87C14B13EA77CBF8A86F293FD30E9B8D57F3C401F9';
var type = 'creative';
const lal = `imapp=${key}&type=${type}`;
fetch('https://facebook.github.io/react-native/movies.json', {
method: 'get',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded', // <-- Specifying the Content-Type
}),
}).then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson.list,
refreshing: false,
});
})
.catch((error) => {
console.error(error);
});
}
componentDidMount() {
this._fetchData();
}
_onRefresh = () => {
() => this.setState({ refreshing: true, });
status = '1';
this._fetchData();
}
render() {
return (
<SafeAreaView>
<View style={{ backgroundColor: '#323232' }}>
<View style={{ flex: 1, paddingTop: 20 }}>
<View style={{ flex: 1, paddingTop: 20 }}>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={({ id }, index) => id}
/>
</View>
</View>
</View>
</SafeAreaView>
);
}
}
Use numColumns in ReactNative Flatlist to render multiple columns & Change your Flatlist as below
<FlatList
data={this.state.dataSource}
renderItem={({ item }) => (
<View style={{ width: '40%', justifyContent: 'space-between', backgroundColor: 'red', margin: 5 }}>
<Text>{item.title}, {item.releaseYear}</Text>
</View>
)}
keyExtractor={item => item.id}
numColumns={2}
/>
Change this according to your requirements.
Hope this helps you. Feel free for doubts.
Related
I'm using hooks in react native project and setting data variable with referenced firebase database, when I'm console logging this data variable, It is showing null at first and within few seconds it shows fetched data, but flatlist is not reading it. Please correct my mistake. Here is my code:
RecommenTab = () => {
useFirebaseQuery = ref => {
const [docState, setDocState] = useState({
isLoading: true,
data: null
});
useEffect(() => {
return ref.on("value", snapshot => {
setDocState({
isLoading: false,
data: snapshot
});
});
}, []);
return docState;
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "#CED0CE",
marginLeft: "14%"
}}
/>
);
};
userList = () => {
const ref = database.ref("users");
const { isLoading, data } = this.useFirebaseQuery(ref);
if (data != []) {
return (
<SafeAreaView style={{ marginTop: 20 }}>
{console.log(data)}
<Text>SHOW</Text>
<FlatList
data={data}
renderItem={({ item }) => (
<View>
<Text>Work</Text>
<ListItem
title={item.name}
subtitle={item.username}
leftAvatar={{
rounded: true,
source: { uri: item.avatar }
}}
/>
</View>
)}
keyExtractor={item => item.id}
ItemSeparatorComponent={this.renderSeparator}
/>
</SafeAreaView>
);
}
};
return <View>{this.userList()}</View>;
};
I'm getting activity indicator after 20 posts as the offset number is set to 20 and after each scroll its loading more content but I want it to stop loading (Activity Indicator) when reached at the end of the data and there is no data to fetch.
Here is all the default states:
this.state = {
data: [],
dataProvider: new DataProvider((item1, item2) => {
return item1.ID !== item2.ID;
}),
isLoading: false,
};
Here is the render of the component:
render(){
if( !this.state.data.length ) {
return(
<ActivityIndicator
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}
size='large'
color='#0A80FE'
/>
);
}
return(
<>
<View style={{flex:1}}>
<RecyclerListView
style={{ flex: 1 }}
onEndReached={() => {
this.getData();
//(ignore this as this is required for recyclerlist view)
this.setState({});
}}
onEndReachedThreshold={1000}
dataProvider={this.state.dataProvider}
rowRenderer={this.renderItem}
renderFooter={this.renderFooter}
/>
</View>
</>
);
Here is the getData function:
getData = () => {
if(this.state.isLoading){
return;
}
this.setState({
isLoading: true
});
const url = 'some url?offset=' + this.state.data.length;
fetch(url).then((response) => response.json())
.then((responseJson) => {
this.setState({
data: this.state.data.concat(responseJson.posts),
dataProvider: this.state.dataProvider.cloneWithRows(
this.state.data.concat(responseJson.posts)
),
})
})
.catch((error) => {
console.error(error);
}).finally(() => {
this.setState({
isLoading: false,
})
})
}
Here's renderItem function:
renderItem = (type, item ) => (
<ListItem
containerStyle={{height: 120}}
title={item.title}
subtitle={item.author.name}
leftAvatar={avatar}
bottomDivider
/>
);
And here is renderFooter function:
renderFooter = () => {
return !this.isLoading
? <ActivityIndicator
style={{ marginVertical: 10 }}
size='large'
color='#0A80FE'
/>
: <View style={{ height: 60 }}>
<Text style={{color: '#ccc', textAlign: 'center', paddingVertical: 10,}}> You've reached at the end of the posts.</Text>
</View>;
};
renderFooter always sets to loading even if I reached at the end of the posts resulting in an unending activity indicator
I made a Like function with React and Flask API, it works pretty well, it makes the Like action but it only appears when I refresh the whole list. Somehow I want to refresh the Like picture and the Like count at the post.
I tried to put extraData in my FlatList but that does not solve my problem...
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
const action = this.props.has_liked? 'unlike':'like'
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
action: action
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error)
});
this.setState({liked: action})
}
render() {
const img = this.props.has_liked? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')
return(
<View style={{flex:1, marginTop: 10, marginBottom:16, left: 20}}>
<View style={{flex: 1, flexDirection: 'row'}}>
<Image source={this.props.image_uri} style={{height:42, width: 42, borderRadius:21}}/>
<Text style={{left:20,paddingTop:6}}>{this.props.author}</Text>
<Text style={{position: 'absolute', right: 40, paddingTop:6,fontSize:12,color:'#babbbc'}}> {this.props.date} </Text>
</View>
<View style={{flex:1, left: 60, right:20,width: '70%', marginTop:-10}}>
<Text style={{fontWeight:'bold',fontSize:18,marginBottom:6}}>{this.props.title} </Text>
<Text style={{fontSize:16,marginBottom:6 }}>{this.props.content}</Text>
<View style={{flex: 1, flexDirection: 'row'}}>
<TouchableOpacity onPress={this.handleClick}>
<Image style={{width:24, height:24, marginBottom:6, marginTop:6}} source={img} />
</TouchableOpacity>
<Text style={{paddingTop:10, marginLeft:6, fontSize:14,color:'#bfbfbf'}}>{this.props.likes}</Text>
</View>
</View>
</View>
);
}
}
<FlatList
data={this.state.dataSource}
extraData={this.state}
renderItem={({item}) => <PostView title={item.title}
content={item.content}
author={item.author}
date={item.date_posted}
likes={item.likes}
has_liked={item.has_liked}
jwt = {this.props.screenProps.jwt}
id = {item.id}
image_uri={{uri:'http://127.0.0.1:5000/static/profile_pics/'+item.profile_image}}/> }
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh}
keyExtractor={item => item.id}/>
</View>
extraData :
extraData={{this.state}}
and put this.setState({liked: action}) here:
.then((response) => {
console.log(response.data);
this.setState({liked: action})
})
try with in home
this.state = {
loading: true,
email: '',
error: '',
refreshing: false,
dataSource: [],
updated: false
}
handleChange = () => {
this.setState({ updated: true })
}
handleRefresh = () => {
this.setState({
refreshing: true,
data: this.state.dataSource
}, () => {
this.makeRemoteRequest()
})
}
Replace
<PostView title={item.title}
....
/>
with
<PostView title={item.title}
.....
handleChange={this.handleChange}/>
extraData={this.state}
and update
and
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
if(response.data.account == "liked"){
this.setState({liked:true})
}else{
this.setState({liked:false})
}
})
.catch((error) => {
console.log(error)
});
}
with
handleClick() {
const headers = {
'Authorization': 'jwt ' + this.props.jwt
};
axios.post("http://127.0.0.1:5000/API/likeaction",{
id: this.props.id,
}, {
headers: headers
})
.then((response) => {
console.log(response.data);
this.props.handleChange(true);
if(response.data.account == "liked"){
this.setState({liked:true})
}else{
this.setState({liked:false})
}
})
.catch((error) => {
console.log(error)
});
}
const img = this.state.liked? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')
with
const img = this.state.liked ? require('../assets/icons/heart-filled.png') : require('../assets/icons/heart-no-fill.png')
I have a project where I am fetching from an API some data and I am rendering those data in React Native. After rendering, I am displaying a list of documents and when I click in one of them I pass some values to next page which includes Name, Description of the document and input fields. Then I sign the document.
So, I want to log all these values (Title, description, user input values and user signature) and POST them using fetch() to my server.
Please let me know if you need further explanation, thanks for any suggestion!
Here is the code of the class where I am displaying everything, I dont think you will need the homepage code:
class DetailScreen extends React.Component {
state = {
isModalVisible: false
};
_toggleModal = () =>
this.setState({ isModalVisible: !this.state.isModalVisible });
constructor(props) {
super(props);
this.state = {
signature: null,
}
this.postToBmp();
}
static navigationOptions = {
title: 'Content of selected'
};
handleSignature = signature => {
this.setState({ signature }), this.setState({ isModalVisible: false });
};
postToBmp = () => {
fetch('https://myurl', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Connection': 'Keep-Alive',
},
credentials: 'include',
body: JSON.stringify({
from: 'test#test.dk',
attachmentName: 'The PDF file name',
recipientFullName: 'My name',
to: [
'<test#test.com>'
]
})
})
}
renderTextandInputs = (obje) => {
console.log("KEYVALUES:", obje.keyValues)
var keyvalue_to_json = JSON.parse(obje.keyValues);
var foundTextFields = [];
for (let i = 0; i < keyvalue_to_json.length; i++) {
if (keyvalue_to_json[i].type === 'textfield') {
foundTextFields.push(<TextInput style={{ borderWidth: 1, flex: 1, alignItems: 'flex-start' }}>{keyvalue_to_json[i].placeholderText}</TextInput>)
}
}
return (
<View>
<ListItem
title={obje.name}
subtitle={obje.description}
/>
<View >
{foundTextFields}
</View>
</View>
)
}
render() {
const style = `.m-signature-pad--footer
.button {
background-color: red;
color: #FFF;
}`;
const obj = this.props.navigation.state.params.item;
var propsArray = [];
const itemArray = Object.assign(obj)
propsArray.push(itemArray)
keyExtractor = (item, index) => {
return index.toString();
}
return (
<View style={{ flex: 1, justifyContent: "center" }}>
<View style={{ flex: 1, alignItems: 'stretch' }}>
<FlatList
key={propsArray.key}
data={propsArray}
renderItem={({ item }) => this.renderTextandInputs(item)}
/>
</View>
<View >
{this.state.signature ? (
<Image
resizeMode={"contain"}
style={{ width: 150, height: 114 }}
source={{ uri: this.state.signature }}
/>
) : null}
</View>
<Modal isVisible={this.state.isModalVisible}
onBackdropPress={() => this.setState({ isModalVisible: false })}
>
<View style={{ flex: 1 }}>
</View>
<Signature
width="100"
onOK={this.handleSignature}
descriptionText="Please draw your signature"
clearText="Clear"
confirmText="Save"
webStyle={signature_styles}
/>
</Modal>
<View>
<Button title="SIGN" onPress={this._toggleModal} />
</View>
</View>
);
}
Here is a screenshot of the home page where I am displaying a list of documents from API:
This is a screenshot of second page where I displaying name, description, textinputs from API and I sign the document using a component:
I currently have a screen that lists items with star ratings on them.
This is created due to the following JSX being returned by a _renderItem function for a FlatList component. :
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: info.item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={info.item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{info.item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={2} /*I want to change this to be dynamic */
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: info.item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
What i would like to do, is dynamically fetch data (from an API) and pass the user's ratings for each item into the startingValue prop of the Rating component.
The API if called returns an array. So accessing response[0] gives you an object similar to this (values depending on if its an activity or diet rating etc):
{
"ActivityTotalScore": null,
"DietTotalScore": 1,
},
So i thought a function roughly like so would work, but i can't figure out how to pass it to that prop. Note - info.item.id is the title of the rendered item in question. So it is equal to 'Activity' or 'Weight' etc
getScore(info){
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
return response[0][info.item.id+'TotalScore'] ;
}
)
}
The simple way is to create a new Component that representents your card. It could be
// In AssessCard.js
import React from 'react';
// Others imports
export default class AssessCard extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
rating: 0,
item: props.item
};
}
componentDidMount() {
this._loadRating();
}
_loadRating() {
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
this.setState({ rating: response[0][info.item.id+'TotalScore'] }); // HERE WE'RE SAVING THE RATING
}
)
}
render() {
const { rating, item } = this.state;
return (
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={rating} // HERE WE USE RATING PROP OF THIS COMPONENT
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
);
}
}
//in file contening your _renderItem function
import AssessCard from './somewhere/AssessCard';
/* CODE */
_renderItem (info) => {
return <AssessCard item={info.item} />
}