I have just started to learn React Native, and this is my first project - a news app. However, I have successfully rendered the image and description of the news using React Native Flatlist.
But when I am using numColumns for making two columns, the column number remains the same. But the number of the shown images becomes the half (i.e. from 18 to 9 in my case). And also the description of the image is going under the image of the next news like shown below -
My source code looks like below -
import React, { Component } from 'react'
import { View, Text, FlatList, TouchableHighlight, SectionList, TouchableOpacity , Image,StyleSheet } from 'react-native'
import { ScrollView } from 'react-native-gesture-handler';
import { HomeNewsJSON } from "../../../../assects/JSON/Home"
class HomeNews extends Component {
constructor(props) {
super(props);
this.state = {
news: ""
};
}
componentDidMount() {
this.getInfo();
}
getInfo() {
var data = []
var jsondata = HomeNewsJSON["items"]
// alert(jsondata.length)
this.setState({
news: jsondata
})
}
renderImage(item) {
var a = item;
return (
<TouchableOpacity
style={{flex:1/3,
aspectRatio:1}}>
<Image style={{flex: 1}} resizeMode='cover' source={{ uri: (a.slice(a.indexOf("src") + 5, a.indexOf("</a>") - 3))}}></Image>
</TouchableOpacity>
)
}
renderPic(data) {
var a = data;
return (a.slice(a.indexOf("src") + 5, a.indexOf("</a>") - 3));
}
render() {
var result = Object.entries(this.state.news);
console.log(result)
return (
<View>
<FlatList
contentContainerStyle={{margin:2}}
style={{borderWidth: 0}}
horizontal={false}
numColumns={2}
keyExtractor={item => item.findIndex}
data={result}
renderItem={({ item }) => (
<View>
{this.renderImage(item[1]["description"])}
<Text>{item[1]["description"]}</Text>
</View>
)}
/>
</View>
)
}
}
export default HomeNews
Please, anyone, suggest me a way to fix it. I really appreciate any help you can provide.
try flex:1 with View outside of item
renderItem={({ item }) => (
<View
style={{
flex: 1,
flexDirection: 'column',
}}>
//image here
</View>
)
Let's try add flexDirection : 'row' in view, such as:
<View style={{flexDirection : 'row'}}>
{this.renderImage(item[1]["description"])}
<Text>{item[1]["description"]}</Text>
</View>
Related
I am getting a list of data using map not flatlist, I want to use .map not flatlist, when I apply ActivityIndicator to it while fetching the data, it did not work see below
Below is my code
<View>
{dataList.map((dataList, index) =>
<Text key={index} >{dataList.category_name}</Text>
<Text key={index} >{dataList.category_number}</Text>
)}
</View>
When I tried it with ActivityIndicator see below
{ dataList ?
<View>
{dataList.map((dataList, index) =>
<Text key={index} >{dataList.category_name}</Text>
<Text key={index} >{dataList.category_number}</Text>
)}
</View>
:
<ActivityIndicator />
}
It the not work, I will need your help with this.
Thanks in advance
Try using a boolean for your conditional render such as a loading state which you can easily toggle on and off at the beginning of the fetch and at the end respectively. You can also state the logic of your map outside of your component so it looks way cleaner and easy to read like this example:
import React from 'react';
import { Text, View, ActivityIndicator } from 'react-native';
const dataList = [
{ category_name: 'pop', category_number: 1 },
{ category_name: 'dance', category_number: 2 },
{ category_name: 'hiphop', category_number: 3 },
];
const renderDataList = () => {
return dataList.map((dataList, index) => (
<View>
<Text>{dataList.category_name}</Text>
<Text>{dataList.category_number}</Text>
</View>
));
};
const App = () => {
const [isLoading, setIsloading] = React.useState(false);
return <View>{isLoading ? <ActivityIndicator /> : renderDataList()}</View>;
};
export default App;
Your output would be for false:
Your output for true would be:
I have a webview component like this:
export default class Home extends React.Component {
onMessage(m) {
//Update an input field in the webview with a custom value
}
render(){
let jsCode = '';
return (
<WebView
ref={(webView) => { this.webView.ref = webView; }}
injectedJavaScript={jsCode}
url={this.state.url}
onMessage={m => this.onMessage(m)}
/>
)
}
}
The webpage has an input field with an id='inpOne'. onMessage prop is triggered by a button click inside the webpage. How to update the input field with the above id when the onMessage prop is executed?
Stripped most of the code for brevity.
Probably like this.
export default class Home extends React.Component {
onMessage(m) {
const js = `document.getElementById('inpOne').value = ${m};`
this.webView.injectJavaScript(js);
}
}
Also, check your WebView's ref prop definition. It looks incorrect. Should be ref={ref => (this.webView = ref)}
Here is the full code of how to change HTML inside of WebWiew from React Native
import React, { Component } from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import { WebView } from 'react-native-webview';
export default class Sample extends Component {
constructor(props) {
super(props);
}
sendDataFromReactNativeToWebView() {
let injectedData = `document.getElementById("login_field").value = 'xyz#github.com';`;
this.webView.injectJavaScript(injectedData);
}
render() {
return (
<View style={{ flex: 1, marginTop: 30 }}>
<TouchableHighlight style={{ padding: 10, backgroundColor: 'gray', marginTop: 20 }} onPress={() => this.sendDataFromReactNativeToWebView()}>
<Text style={{ color: 'white' }}>Send Data To WebView from React Native</Text>
</TouchableHighlight>
<WebView
style={{ flex: 1 }}
source={{ uri: 'https://github.com/login' }}
ref={(webView) => this.webView = webView}
/>
</View>
);
}
}
I'm making a view in react native but my component has a webview to display HTML, below the webview is a flatlist( list of items)
The parent component is supposed to be scrollable based on the webview & the flatlist.
I tried to put them together but it doesn't work as I want.
Therefore I would appreciate all of your advice & suggestions. Thank you
Updated:
I found out a solution here after the owner of the lib has been updated
https://github.com/iou90/react-native-autoheight-webview/issues/81
You can use WebView as a header component of FlatList as this:
<View style={styles.container}>
<FlatList
data={[
{ key: 'a' },
{ key: 'b' },
{ key: 'c' },
{ key: 'd' },
]}
renderItem={({ item }) => <Text>{item.key}</Text>}
ListHeaderComponent={
<View style={{ height: 200 }}>
<WebView
originWhitelist={['*']}
source={{ html: '<h1>Hello world</h1>' }}
/>
</View>
}
/>
</View>
But there is still a limitation, you have to specify the height of the view that wraps WebView as done above.
Hope, you got the idea ?
Maybe this will help.
import React, { Component } from 'react';
import { Text, View, StyleSheet, WebView, FlatList } from 'react-native';
export default class App extends Component {
onNavigationStateChange = navState => {
if (navState.url.indexOf('https://www.google.com') === 0) {
const regex = /#access_token=(.+)/;
let accessToken = navState.url.match(regex)[1];
console.log(accessToken);
}
};
render() {
const url = 'https://api.instagram.com/oauth/authorize/?client_id={CLIENT_ID}e&redirect_uri=https://www.google.com&response_type=token';
return (
<View style={{flex: 1}}>
<WebView
source={{
uri: url,
}}
scalesPageToFit
javaScriptEnabled
style={{ flex: 1 }}
/>
<FlatList data={[1, 2, 3]} renderItem={(item) => <Text>item</Text>}/>
</View>
);
}
}
import React from 'react';
import {SafeAreaView, KeyboardAvoidingView, FlatList, View, Text, TextInput, Button, StyleSheet } from 'react-native';
export default class Guest extends React.Component {
state={
command: '',
}
constructor(props) {
super(props)
this.onChangeText = this.onChangeText.bind(this)
this.onKeyPress = this.onKeyPress.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChangeText(text){
const command = text.replace('\n', '');
this.setState({
command: command
})
}
onKeyPress(e){
}
onSubmit(){
}
render() {
return(
<SafeAreaView style={styles.safeAreaView}>
<KeyboardAvoidingView style={styles.keyboardAvoidingView} keyboardVerticalOffset={88} behavior="padding" enabled>
<FlatList
inverted={true}
keyboardShouldPersistTaps='always'
keyboardDismissMode='interactive'
ref='list'
style={styles.flatList}
data={[1, 2, 3]}
renderItem={(props) => {
return(<View><Text>{props.item}</Text></View>)
}}
/>
<TextInput
command={this.state.command}
onChangeText={this.onChangeText}
onKeyPress={this.onKeyPress}
onSubmit={this.onSubmit}
style={styles.textInput}
/>
</KeyboardAvoidingView>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
safeAreaView:{
backgroundColor:"#ffffff",
},
keyboardAvoidingView:{
},
flatList:{
backgroundColor: 'red',
},
textInput:{
backgroundColor: 'yellow'
}
})
I'd like the red flatList to fill the screen (but keep height of yellow textbox).
I've tried flex:1 on flatList, but it simply makes it disappear.
FlatList inherits ScrollView's props, so solution for ScrollView will work:
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
{...otherProps}
/>
Here is the original Github issue for above solution.
EDIT: The parental Views of FlatList should have flex: 1 in their style.
safeAreaView:{
backgroundColor:"#ffffff",
flex: 1
},
keyboardAvoidingView:{
flex: 1
},
use the property style wit flex:
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
keyExtractor = { this.keyExtractor }
data = { this.getPOs() }
ListEmptyComponent = { this.renderEmpty }
ItemSeparatorComponent = { Separator }
renderItem = { this.renderItem }
/>
</View>
)
}
No need to add a parental view to the list, simply:
render() {
return <FlatList style={{width: '100%', height: '100%'}}
{...others}
/>;
}
you can also add height in flatList style or put flatlist inside a view and then add flex for view
In my case the problem was with virtual keyboard. when I open another page. then the keyboard suddenly dismiss. and it cause part of the page to be like someone cut it or clean it. so the solution is to before push the page that contain flatlist first dismiss the keyboard and then navigate to new page
I try every response on this issue but none of them work.
What I do was add a Parent to the FlatList and then give it a style :
<View style={{ height: SCREEN_HEIGHT}}>
SCREEN_HEIGHT is from Dimensions.get('window')
you have to import from "react-native" like this:
import { Dimensions } from "react-native"
Full example:
<View style={{ height: SCREEN_HEIGHT}}>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
keyExtractor={item => item.name}
numColumns={1}
data={this.state.dataList}
renderItem={({ item, index }) =>
this._renderItemListValues(item, index)
}
/>
</View>
I've 4 FlatLists with maxHeight set to 200 inside a ScrollView.
<ScrollView>
<FlatList/>
<FlatList/>
<FlatList/>
<FlatList/>
</ScrollView>
and when I try to scroll a FlatList, it doesn't scroll but the ScrollView scrolls. How do I fix this issue ?
Full Source Code
import { Component, default as React } from 'react';
import { FlatList, ScrollView, Text } from 'react-native';
export class LabScreen extends Component<{}> {
render() {
return (
<ScrollView>
{this.renderFlatList('red')}
{this.renderFlatList('green')}
{this.renderFlatList('purple')}
{this.renderFlatList('pink')}
</ScrollView>
);
}
getRandomData = () => {
return new Array(100).fill('').map((item, index) => {
return { title: 'Title ' + (index + 1) };
});
};
renderFlatList(color: string) {
return (
<FlatList
data={this.getRandomData()}
backgroundColor={color}
maxHeight={200}
marginBottom={50}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>
);
}
}
snack.expo link
We can use the built-in nestedscrollenabled prop for the children FlatList/ScrollView components.
<FlatList nestedScrollEnabled />
This is only required for Android (Nested scrolling is supported by default on iOS).
I was having a very similar issue until I came across an almost complete solution in a very helpful comment on one of the GitHub issues for the react-native project: https://github.com/facebook/react-native/issues/1966#issuecomment-285130701.
The issue is that the parent component is the only one registering the scroll event. The solution is to contextually decide which component should actually be handling that event based on the location of the press.
You'll need to slightly modify your structure to:
<View>
<ScrollView>
<View>
<FlatList />
</View>
<View>
<FlatList />
</View>
<View>
<FlatList />
</View>
<View>
<FlatList />
</View>
</ScrollView>
</View>;
The only thing I had to change from the GitHub comment was to use this._myScroll.contentOffset instead of this.refs.myList.scrollProperties.offset.
I've modified your fully working example in a way that allows scrolling of the inner FlatLists.
import { Component, default as React } from "react";
import { View, FlatList, ScrollView, Text } from "react-native";
export default class LabScreen extends Component<{}> {
constructor(props) {
super(props);
this.state = { enableScrollViewScroll: true };
}
render() {
return (
<View
onStartShouldSetResponderCapture={() => {
this.setState({ enableScrollViewScroll: true });
}}
>
<ScrollView
scrollEnabled={this.state.enableScrollViewScroll}
ref={(myScroll) => (this._myScroll = myScroll)}
>
{this.renderFlatList("red")}
{this.renderFlatList("green")}
{this.renderFlatList("purple")}
{this.renderFlatList("pink")}
</ScrollView>
</View>
);
}
getRandomData = () => {
return new Array(100).fill("").map((item, index) => {
return { title: "Title " + (index + 1) };
});
};
renderFlatList(color: string) {
return (
<View
onStartShouldSetResponderCapture={() => {
this.setState({ enableScrollViewScroll: false });
if (
this._myScroll.contentOffset === 0 &&
this.state.enableScrollViewScroll === false
) {
this.setState({ enableScrollViewScroll: true });
}
}}
>
<FlatList
data={this.getRandomData()}
backgroundColor={color}
maxHeight={200}
marginBottom={50}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => <Text>{item.title}</Text>}
/>
</View>
);
}
}
Hopefully you find this useful!
This is the simplest answer that requires zero configuration.. and it works like a charm
<ScrollView horizontal={false}>
<ScrollView horizontal={true}>
<Flatlist
....
....
/>
</ScrollView>
</ScrollView>
I fixed my problem with nested FlatList not being able to scroll items on android by simply importing FlatList
import { FlatList } from 'react-native-gesture-handler';
If this would not work, also try to import ScrollView.
import { ScrollView } from 'react-native';
// OR
import { ScrollView } from 'react-native-gesture-handler';
You need to play around with these imports, at least it worked in my case.
Try to set the FlatList as nested
nestedScrollEnabled={true}
Using View with a flex:1 instead of ScrollView worked for me.
Use map instead of Flatlist, same result and don't break the application
Minha conta
{
buttonsProfile.map(button => (
<ArrowButton
key={button.key}
title={button.title}
iconName={button.icon}
toogle={button.toogle}
onPress={() => {navigation.navigate(button.route)}}
/>
))
}
The better answer is to put a horizontal ScrollView inside of the other ScrollView and then the FlatList