i have a component "Address" were i am using google-places-autocomplete for getting address.After that i extract the needed data (such as Country,postal code etc). And now i want to transfer this data into the "Main Component" for where the is getting called. In Address Component, i have used useState() to store data.
import { View, StyleSheet, TextInput } from "react-native";
import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete";
import { } from "react-native";
import Colors from "../constants/Colors";
let places = [];
const Address = (props) => {
const [place, setPlace] = useState();
const [postalCode, setPostalCode] = useState();
const [country, setCountry] = useState();
const [state, setState] = useState();
const [city, setCity] = useState();
const setCountryHandler=(value)=>{
setCountry(value)
}
const setPostalCodeHandler=(value)=>{
setPostalCode(value)
}
const setCityHandler=(value)=>{
setCity(value);
}
const setStateHandler=(value)=>{
setState(value)
}
return (
<View style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
marginVertical: 10,
}}>
<View
style={styles.search}
>
<GooglePlacesAutocomplete
placeholder="Address"
onPress={(data,details=null)=>{
let address = details.address_components;
let address1 = [];
for (let i = 0; i < 1; i++) {
for (let i in address) {
address1 = address[i].types;
for (let j in address1) {
if (address1[j] === "sublocality") {
places.push(address[i].long_name);
}
}
}
setPlace(places);
places = [];
}
for (let i in address) {
address1 = address[i].types;
for (let j in address1) {
if (address1[j] === "locality") {
setCityHandler(address[i].long_name);
}
}
}
for (let i in address) {
address1 = address[i].types;
for (let j in address1) {
if (address1[j] === "administrative_area_level_1") {
setState(address[i].long_name);
}
}
}
for (let i in address) {
address1 = address[i].types;
for (let j in address1) {
if (address1[j] === "country") {
setCountry(address[i].long_name);
}
}
}
for (let i in address) {
address1 = address[i].types;
for (let j in address1) {
if (address1[j] === "postal_code") {
setPostalCode(address[i].long_name);
}
}
}
}}
enablePoweredByContainer={false}
disableScroll={false}
fetchDetails={true}
query={{
key: "#############################",
language: "en",
}}
styles={{
textInputContainer: {
width: "100%",
},
}}
/>
</View>
<View
style={{ justifyContent: "center", alignItems: "center", width: "80%" }}
>
<View style={styles.container}>
<TextInput placeholder="city" defaultValue={city} onChangeText={setCityHandler}/>
</View>
<View style={styles.container}>
<TextInput placeholder="state" defaultValue={state} onChangeText={setStateHandler}/>
</View>
<View style={styles.container}>
<TextInput placeholder="country" defaultValue={country} onChangeText={setCountryHandler} />
</View>
<View style={styles.container}>
<TextInput placeholder="pincode" defaultValue={postalCode} onChangeText={setPostalCodeHandler}/>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
marginVertical: 10,
width: "100%",
paddingVertical: 8,
paddingHorizontal: 8,
borderColor: Colors.accent,
borderWidth: 1,
borderRadius: 6,
backgroundColor: "white",
},
search:{
marginBottom:10,
width: "80%",
borderColor: Colors.accent,
borderWidth: 1,
borderRadius: 6,
backgroundColor: "white",
}
});
export default Address;
here's my code and i want to transfer data =city,state,postalcode,country into another component
To transfer data , to another component , that Component will need to be the Child Component of your Address Component, in this way child component will receive Address Component states as props.
That's why people use Redux, which creates container and stores all your states in that container, which then can be accessed by any component in your project.
https://react-redux.js.org/
But if your components are not related, and you don't want to use redux , then there is one way to do this is, that you
save your state value to the storage via Async Storage.
https://github.com/react-native-async-storage/async-storage
and then retrieve those values in Main Component via AsyncStorage.
Related
How to open the default Contact app in react native using Expo?
my requirements are:
Display a button to open the contact book on home screen.
On clicking the button, open the list of contacts in user's phone.
On contact list, each contact item should display the contact's profile picture, full name and the number/type of number(Home/work)
Add a search bar that will allow the user to search contacts by name
Once the user selects a contact, go back to home screen and display the chosen contact's phone number in a text field(not as an alert/toast).
If a contact has multiple phone numbers, allow the user to pick only one phone number.
import React, { useEffect, useState } from "react";
import {
StyleSheet,
View,
Text,
TextInput,
FlatList,
ActivityIndicator,
} from "react-native";
import * as Contacts from "expo-contacts";
export default function App() {
const [allcontacts, setcontact] = useState([]); //say set main state
const [allcontactsfilter, setcontactfilter] = useState([]); // filter state
const [searchcontact, setsearchcontact] = useState("");
const [loading, setloading] = useState(false);
console.log(searchcontact);
useEffect(() => {
(async () => {
const { status } = await Contacts.requestPermissionsAsync();
if (status === "granted") {
const { data } = await Contacts.getContactsAsync({
fields: [
Contacts.Fields.PhoneNumbers,
// Contacts.Fields.Emails
],
});
// console.log("collectio object", data);
if (data.length > 0) {
// console.log("contact hellos", data);
setcontact(data);
setting same data in two-state help to manipulate state when we do filtering
process
setcontactfilter(data);
setloading(false);
}
}
})();
setloading(true);
}, []);
filter function
const filtercontacts = (e) => {
const filtervalue = allcontactsfilter.filter((contact) => { <-- look here at
allcontactsfilter
let lowercase = `${contact.firstName} ${contact.lastName}`.toLowerCase();
let searchlowercase = e.toLowerCase();
return lowercase.indexOf(searchlowercase) > -1;
});
setsearchcontact(setcontact(filtervalue));
};
return (
<View style={styles.container}>
<TextInput
style={{
backgroundColor: "#D5D5D5",
height: 40,
width: "90%",
borderBottomWidth: 0.3,
borderBottomColor: "#ddd",
}}
placeholder="search"
value={searchcontact}
onChangeText={filtercontacts}
/>
{loading ? (
<View>
<ActivityIndicator size={35} color="green" />
</View>
) : null}
<FlatList
data={allcontacts}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (
<View style={{ minHeight: 70, padding: 5 }}>
<Text>
{/* {
("inside flatlist>>>,....",
console.log(
item.phoneNumbers == undefined || null
? []
: item.phoneNumbers[0]?.number
))
} */}
{item?.firstName == null
? "please update name in your phone contact book"
: item.firstName}
{item?.lastName == null ? null : item.lastName}
</Text>
<Text style={{ color: "red" }}>
{item.phoneNumbers == undefined || null
? []
: item.phoneNumbers[0]?.number}
</Text>
</View>
)}
ListEmptyComponent={() => (
<Text style={{ fontSize: 20, marginVertical: 40 }}>No contact </Text>
)}
/>
{/* {console.log("okstate..", allcontacts)} */}
<Text>Contacts Module Example </Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
apply style according to your need.
I am developing an app That contain an image uploader. I found some code on internet that can upload image. And it worked partially. Which means When i press the choose image button, it opens gallery and i am able to select and crop image. And after cropping when i select ok nothing happen. It just show the image and its not uploading to the firebase cloud. Here is my code.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Button,
Image,
ActivityIndicator,
TouchableOpacity
} from 'react-native';
import * as firebase from 'firebase';
import RNFetchBlob from 'react-native-fetch-blob';
import ImagePicker from 'react-native-image-crop-picker';
export default class RNF extends Component {
constructor (props) {
super(props);
this.state = {
loading: false,
dp: null
};
}
openPicker () {
this.setState({ loading: true });
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
// const { uid } = this.state.user
const uid = '12345';
ImagePicker.openPicker({
width: 300,
height: 300,
cropping: true,
mediaType: 'photo'
}).then(image => {
const imagePath = image.path;
let uploadBlob = null;
const imageRef = firebase.storage().ref(uid).child('dp.jpg');
let mime = 'image/jpg';
fs.readFile(imagePath, 'base64')
.then((data) => {
// console.log(data);
return Blob.build(data, { type: `${mime};BASE64` });
})
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime });
})
.then(() => {
uploadBlob.close();
return imageRef.getDownloadURL();
})
.then((url) => {
let userData = {};
// userData[dpNo] = url
// firebase.database().ref('users').child(uid).update({ ...userData})
let obj = {};
obj['loading'] = false;
obj['dp'] = url;
this.setState(obj);
})
.catch((error) => {
console.log(error);
});
})
.catch((error) => {
console.log(error);
});
}
render () {
const dpr = this.state.dp ? (<TouchableOpacity onPress={ () => this.openPicker() }><Image
style={{ width: 100, height: 100, margin: 5 }}
source={{ uri: this.state.dp }}
/></TouchableOpacity>) : (<Button
onPress={ () => this.openPicker() }
title={ 'Change Picture' }
/>);
const dps = this.state.loading ? <ActivityIndicator animating={this.state.loading} /> : (<View style={styles.container}>
<View style={{ flexDirection: 'row' }}>
{ dpr }
</View>
</View>);
return (
<View style={styles.container}>
{ dps }
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF'
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5
}
});
AppRegistry.registerComponent('RNF', () => RNF);
I want to increase a particular static variable each time when data will receive within onMessageArrived(). Means in onMessageArrived method when new data will come from mqtt, want to increase the a static variable which is initially set with 0. Can anybody please help me to achieve that. I am a beginner in react native. Thanks in advance.
import React, { Component } from 'react';
import init from 'react_native_mqtt';
import { AsyncStorage, StyleSheet, Text, View } from 'react-native';
import Pie from 'react-native-pie';
init({
size: 10000,
storageBackend: AsyncStorage,
defaultExpires: 1000 * 3600 * 24,
enableCache: true,
sync: {},
});
export default class MqttLog extends Component {
constructor(props) {
super(props);
const client = new Paho.MQTT.Client('iot.eclipse.org', 443, 'uname');
client.connect({ onSuccess: this.onConnect, useSSL: true });
client.onConnectionLost = this.onConnectionLost;
client.onMessageArrived = this.onMessageArrived;
this.state = {
text: '10',
client,
};
}
onConnect = () => {
const { client } = this.state;
client.subscribe('WORLD');
// this.pushText('connected');
console.log('connect');
};
onConnectionLost = responseObject => {
if (responseObject.errorCode !== 0) {
var connectionLostMessage = `connection lost: ${responseObject.errorMessage}`;
console.log(connectionLostMessage);
// this.pushText(`connection lost: ${responseObject.errorMessage}`);
}
};
onMessageArrived = message => {
var msg = message.payloadString;
var messageResult = `${msg}`;
this.setState({ text: messageResult });
console.log(this.state.text);
};
render() {
// const { text } = this.state;
// console.log(this.state);
return (
<View style={styles.container}>
{/* {text.map(entry => <Text>{entry}</Text>)} */}
{/* <Text>Data</Text>
<Text>{this.state.text}</Text> */}
<Pie
radius={150}
innerRadius={130}
series={[this.state.text, 30, 60]}
colors={['#EAD026', '#FAFAFA', '#EAD026']}
backgroundColor = '#FAFAFA'
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'space-around',
},
gauge: {
position: 'absolute',
width: 100,
height: 100,
alignItems: 'center',
justifyContent: 'center',
},
gaugeText: {
backgroundColor: 'transparent',
color: '#000',
fontSize: 24,
},
});
You can append previous state value with the new value -
let messageResult = `${msg}`;
let oldMessage = this.state.text;
let newMessageIntValue = parseInt(messageResult) + parseInt(oldMessage);
this.setState({text:newMessageIntValue});
NOTE - Let me know in case of any other issue, i have just integrated the MQTT in react native.
I have an app that reads a JSON file. In one tab I have it coming out as a list, on another tab, I want it to show the items selected from the file as the labels for a radio button I found here:
https://www.npmjs.com/package/react-native-radio-buttons-group
Here's the code that I have for the tab of my app that pulls names of medications from a JSON file:
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
TouchableHighlight,
FlatList
} from "react-native";
import { Icon } from 'native-base'
import RadioGroup from 'react-native-radio-buttons-group';
//import MultipleChoice from 'react-native-multiple-choice'
class LikesTab extends Component {
_onSelect = ( item ) => {
console.log(item);
};
onPress = data => this.setState({ data });
constructor(props){
super(props);
this.state = {
data:[]
}
}
//SETTING THE STATE MAKING AN EMPTY ARRAY WHICH WE FIL
// state = {
// data: []
//};
componentWillMount() {
this.fetchData();
}
//Getting the data
fetchData = async () => {
const response = await fetch("https://api.myjson.com/bins/s5iii");
const json = await response.json();
this.setState({ data: json.results });
};
//var customData = require('./customData.json');
//Setting what is shown
render() {
return (
<View style={{ marginVertical: 10, backgroundColor: "#E7E7E7" }} >
<FlatList
data={this.state.data}
keyExtractor={(x, i) => i}
renderItem={({ item }) =>
<Text>
{`${item.name.first} ${item.name.last}`}
</Text>}
/>
</View>
);
}
}
export default LikesTab;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
});
Here's my tab for the radio button
import React, { Component } from 'react';
import { Text, View, StyleSheet } from 'react-native';
import RadioGroup from 'react-native-radio-buttons-group';
export default class AddMediaTab extends Component {
componentWillMount() {
this.fetchData();
}
//Getting the data
fetchData = async () => {
const response = await fetch("https://api.myjson.com/bins/s5iii");
const json = await response.json();
this.setState({ data: json.results });
};
state = {
data: [
{
label:' ' ,
}
]
};
// update state
onPress = data => this.setState({ data });
render() {
let selectedButton = this.state.data.find(e => e.selected == true);
selectedButton = selectedButton ? selectedButton.value : this.state.data[0].label;
return (
<View style={styles.container}>
<Text style={styles.valueText}>
Value = {selectedButton}
</Text>
<RadioGroup radioButtons={this.state.data} onPress={this.onPress}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
valueText: {
fontSize: 18,
marginBottom: 50,
},
});
What is your selectedButton variable? I think Value = {selectedButton} is the issue. If selectedButton evaluates to a string, fine but it looks like it is an object in your case. Array.find() returns the first element that satisfies the condition, or if none satisfy it it returns undefined. If that variable undefined during the time it's waiting for your api call to return something that could cause an issue as well.
Greeting everyone,
I am working on react-native FlatList and my problem is that I am unable to scroll to bottom. Here is my FlatList code:
<FlatList style = { styles.list }
ref="flatList1"
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow()}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
scrollNow() {
console.log("******",this.refs);
if(this.refs.flatList1){
this.refs.flatList1.scrollToEnd();
}
}
When the code reaches to
this.refs.flatList1.scrollToEnd();
Error appears on the screen saying
Type Error, cannot read property -1 of undefined.
here is the screenshot.
cannot read property -1 of undefined
I am basically trying to implement chat feature for my application, and therefor i need to scroll to bottom of the list once chat is loaded.
Any kind of help is appreciated.
Thanks
COMPLETE CODE
import React, {
Component
} from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
ActivityIndicator,
TouchableOpacity,
FlatList,
} from 'react-native';
export default class Conversation extends Component {
state = {
conversation_arr: undefined,
last_message_loaded: false,
show_activty_indicator: true,
message_text : undefined,
message_text_length : 0
};
params = this.props.navigation.state;
last_evaluated_key = {
message_id: undefined,
timestamp: undefined
}
conversation = undefined;
thread_info = undefined;
flat_list_height = 0;
static navigationOptions = ({ navigation }) => ({
title: navigation.state.params.header_title,
});
constructor(props) {
super(props);
this._renderItem = this._renderItem.bind(this);
this._fetchConversation();
this.scrollNow = this.scrollNow.bind(this);
this.handleInputTextContent = this.handleInputTextContent.bind(this);
this.sendMessage = this.sendMessage.bind(this);
console.disableYellowBox = true;
this.thread_info = this.params.params.thread_info;
}
// scrollNow() {
// console.log("******",this.refs);
// if(this.refs.flatList1){
// // debugger;
// this.refs.flatList1.scrollToEnd();
// }
// console.log("******", this.flatlist1);
// if(this.flatlist1){
// this.flatlist1.scrollToEnd();
// }
// console.log("###", this.flat_list_height);
// }
scrollNow = () => {
console.log("******", this.flatList1);
if(this.state.conversation_arr && this.state.conversation_arr.length > 0 && this.flatList1){
// debugger;
// setTimeout(() => {
// console.log("timer over now");
this.flatList1.scrollToEnd();
// }, 1000)
// this.flatList1.scrollToEnd();
console.log("Scrolling now at length", this.state.conversation_arr.length);
}
// !!this.refs["myFlatList"] && this.refs["myFlatList"].scrollToEnd()
}
componentDidUpdate(){
console.log("componentDidUpdatecomponentDidUpdate")
}
componentWillUnmount(){
console.log("componentWillUnmountv")
}
render() {
return (
<View style={ styles.container }>
{
this.state.show_activty_indicator &&
<View style={[styles.activity_indicator_container]}>
<ActivityIndicator
animating = { this.state.show_activty_indicator }
size="large"
color="#444444"
/>
</View>
}
<FlatList style = { styles.list }
// inverted
// ref="myFlatList"
// ref={(ref) => this.flatList1 = ref}
ref={(ref) => { this.flatList1 = ref; }}
data = {
this.state.conversation_arr
}
onContentSizeChange={(contentWidth, contentHeight) => {
this.flat_list_height = contentHeight;
// this.scrollNow();
}}
onLayout={this.scrollNow}
renderItem = { this._renderItem }
keyExtractor = { item => item.message_id }
/>
<View style={ styles.bottom_box }>
<Text style={ styles.message_length }> {this.state.message_text_length}/160 </Text>
<View style={ styles.message_box }>
<View style={{flex: 3}} >
<TextInput
style={styles.input_text}
value={this.state.message_text}
onChangeText={this.handleInputTextContent}
placeholder='Type a message here...'
underlineColorAndroid='transparent'
/>
</View>
<View style={{flex: 1}} >
<TouchableOpacity
style={styles.send_button}
onPress={this.sendMessage} >
<Text style={[styles.label_send]}>SEND</Text>
</TouchableOpacity>
</View>
</View>
</View>
</View>
);
}
handleInputTextContent(text){
if(text.length > 160){
text = text.substring(0,159)
this.setState({ message_text : text });
} else {
this.setState({ message_text : text });
this.setState({ message_text_length : text.length });
}
}
sendMessage(){
console.log(this.state.message_text);
if(this.state.message_text && this.state.message_text.length > 0) {
console.log("Send message now");
}
}
_renderItem(item, index){
// console.log(item.item);
item = item.item;
let view = (
<Text style = { [styles.msg_common] }> { item.message_content } </Text>
)
return view ;
}
processPaymentMessages(dataArr) {
return dataArr;
}
_fetchConversation() {
new WebApi().fetchThreadConversation().then(result => {
console.log("resutlresult", result);
if (result && result.data && result.data.LastEvaluatedKey) {
this.last_evaluated_key.message_id = result.data.LastEvaluatedKey.message_id;
this.last_evaluated_key.timestamp = result.data.LastEvaluatedKey.timestamp;
} else {
this.setState({
last_message_loaded: true
});
this.last_evaluated_key = null;
}
if (!this.conversation) {
this.conversation = [];
}
for (let i = 0; i < result.data.Items.length; i++) {
item = result.data.Items[i];
this.conversation.push(item);
}
// console.log(this.conversation);
this.setState({ conversation_arr : this.conversation });
this.setState({ show_activty_indicator : false });
console.log(this.state.conversation_arr.length);
}, error => {
console.log("web api fetch data error", error);
})
}
}
const styles = StyleSheet.create({
activity_indicator_container: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#fff'
},
container: {
flex: 1,
paddingTop: 8,
backgroundColor:"#fff"
},
list : {
paddingLeft: 8,
paddingRight:8,
marginBottom : 85,
},
gray_item: {
padding: 10,
height: 44,
backgroundColor:"#fff"
},
white_item : {
padding: 10,
height: 44,
backgroundColor:"#f5f5f5"
},
msg_common : {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'flex-end',
},
colored_item_common : {
padding : 12,
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
item_insider_common : {
backgroundColor:"#fff",
fontSize : 16,
padding : 12,
borderWidth : 1,
borderRadius : 8,
width : "90%",
fontWeight : "bold",
textAlign: 'center',
},
purple_item_insider : {
color : "#7986cb",
borderColor: "#7986cb",
},
green_item_insider : {
color : "#66bb6a",
borderColor: "#66bb6a",
},
bottom_box:{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flex: 1,
},
message_length: {
height : 20,
textAlign: 'right', alignSelf: 'stretch'
},
message_box: {
// position: 'absolute',
// left: 0,
// right: 0,
// bottom: 0,
flex: 1,
flexDirection: "row"
},
input_text: {
width: '100%',
height: 60,
color: '#000',
backgroundColor:"#eee",
padding: 16,
},
send_button: {
alignItems: 'center',
flex: 1,
height: 60,
padding: 16,
backgroundColor : '#f1592b'
},
label_send: {
color: '#fff'
}
})
You need to give a callback to onLayout like this:
onLayout={this.scrollNow}
The updated code is: I tried it. It works.
import React, { Component } from 'react';
import { FlatList, Text } from 'react-native';
export default class App extends Component {
render() {
return (
<FlatList
ref={(ref) => { this.flatList1 = ref; }}
data={[0, 0, 0, 0, 0, 0, 0, 0]}
onContentSizeChange={(contentWidth, contentHeight) => { this.flat_list_height = contentHeight; }}
onLayout={this.scrollNow}
renderItem={this.renderItem}
keyExtractor={item => item.message_id}
/>
);
}
renderItem =() => <Text style={{marginTop: 100}}>Just Some Text</Text>
scrollNow =() => {
if (this.flatList1) {
this.flatList1.scrollToEnd();
}
}
}
Have you tried passing an empty array when "this.state.conversation_arr" is undefined or null. Checking this._renderItem can be helpful also, weather it is trying to access -1 of any argument.
There are 2 parts wrong in your code.
the ref in FlatList is a function, not a string.
If you don't use arrow function, the FlatList cannot access the "this" in scrollNow() function.
I tested with similar code. The code below should work.
import * as React from 'react';
import { StyleSheet, View, Text, FlatList } from 'react-native';
export default class Conversation extends React.Component {
flatList1;
_interval;
state = { conversation_arr: [] };
componentDidMount() {
let buffer = [];
for (let i = 1; i < 40; i++) {
buffer.push({ message_id: i, message_content: `I'm the message ${i}` });
}
this._interval = setInterval(() => {
this.setState(() => {
return { conversation_arr: buffer };
});
this.flatList1.scrollToIndex({
index: buffer.length - 1,
viewPosition: 1,
viewOffset: 0,
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
render() {
return (
<View style={styles.container}>
<FlatList
ref={ref => {
this.flatList1 = ref;
}}
data={this.state.conversation_arr}
renderItem={this._renderItem}
keyExtractor={item => item.message_id}
getItemLayout={(data, index) => ({
length: 40,
offset: 40 * index,
index,
})}
/>
</View>
);
}
_renderItem = ({ item }) => {
return (
<View>
<Text style={styles.msg_common}>{item.message_content}</Text>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
msg_common: {
height: 40,
fontSize: 18,
paddingHorizontal: 10,
},
});
PS: If you have a long list, let's say more than 100. Using onLayout to scroll down might take some time for initial rendering, which provides a really bad user experience. The much better approach may be
to reverse the list before rendering
provide a sort button and set onRefresh to true during sorting
provide a scroll to bottom button list's footer
Update:
I noticed the onContentSizeChange property is NOT in the documentation.
https://facebook.github.io/react-native/docs/flatlist.html#scrolltoindex
Which version of React-Native are you using?
Update2:
The complete code in TypeScript based on yours. I use setInterval to simulate the delay from API call.
Any async function should be in componentDidMount, because constructor doesn't wait.
getItemLayout is used to help FlatList to figure out height. Notice that this is set before the data arrived.