Big Space between items in FlatList - reactjs

I'm implementing Comment Page like Facebook. Somehow I'm getting a plenty of white space. Check this out!
When I scroll it to the bottom... the rest of comments are there.. so weird
Here is my render function and FlatList
render() {
return (
<RkAvoidKeyboard style={styles.bigContainer} onResponderRelease={(event) => {
Keyboard.dismiss();
}}>
<FlatList
ref='list'
style={styles.root}
data={this.props.comments}
ItemSeparatorComponent={this._renderSeparator}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}/>
{this._renderKeyboard()}
</RkAvoidKeyboard>
)
}
_keyExtractor(item, index) {
return item.id;
}
_renderSeparator() {
return (
<View style={styles.separator}/>
)
}
I set the background color of the FlatList and it colors all screen (except the keyboard and navigation). I didn't notice this until I implement my Keyboard input. So nothing wrong with Keyboard.
This is so werid..!!

To me the space looks exactly the size of keyboard, instead of using the RkAvoidKeyboard spacer, try using react-native-keyboard-spacer
Its easy to set up and you will just have to set it under your comment textInput component or at the bottom of the container whichever suits you.
Here is a sample that I can provide and that may help you
<View>
<FlatList
data = {dataSource}
renderItem = {({item}) => this._renderFlatListItem(item)}
keyExtractor = {(item) => item.id}
/>
<View style={style.textInputContainer}>
<TextInput
placeholder={"Text goes here"}
ref={input => { this.textInput = input }}
onChangeText={(text) => this.setState({currentMessage:text})}
value={this.state.message}
multiline={true}
underlineColorAndroid = {'transparent'}
/>
<TouchableHighlight
underlayColor={'transparent'}
style={style.sendButtonContainer}
onPress = {() => {this._sendMessage();}}>
<Image source={require('../../Assets/Images/shape.png')}
style={style.sendButton} resizeMode="contain"/>
</TouchableHighlight>
</View>
<KeyboardSpacer/>
All the best!

I was getting null for my Avatar Image and that showed huge blank list.
I figured this out while printing all comments on console.
Thank you guys!

Related

How to Limit render element Flat List and add more content in React Native

I want like that flatlist render only 5 checkbox items and then when I click to +5 more button it will show 5 more checkbox list.In this all checkbox list appearing but i want only five
Please help me how to achieve that
Thanks in advance
const renderResourceList = renderData => {
return (
<FlatList
data={renderData}
initialNumToRender={5}
maxToRenderPerBatch={5}
pagingEnabled={true}
nestedScrollEnabled={true}
renderItem={({item}) => (
<View style={styles.card}>
<TouchableOpacity
onPress={() => {
if(resourceTypeArray.includes(item)){
setResourceTypeArray(currentList => {
return currentList.filter(items => items !== item);
});
}
else{
setResourceTypeArray(currentList => [
...currentList,
item
]);
}
onSetResourceType(item);
}}
style={styles.modalBtn}>
<Icon
name={
resourceTypeArray.includes(item) ? 'checkbox-marked' : 'checkbox-blank-outline'
}
size={18}
color="#353C3C"
style={{bottom: -1}}
/>
<View style={styles.textWrapper}>
<Text style={styles.modalText}>{item.charAt(0)}
{item.toLowerCase().slice(1).replace(/_/g, ' ')}</Text>
</View>
</TouchableOpacity>
</View>
)}
/>
);
};
I tried but this not working
I used a package called flatlist-react to handle this for me. A decent tutorial for this can be found here.
With this package, you can directly specify and limit the items rendered with the limit prop. Here is an example:
<FlatList
limit="2,-2"
list={people}
renderItem={Person}
/>
If you keep track of the limit prop variables using state, you can dynamically change these values when you click 5+ more in order to render whatever part of your data you would like.

React Native: Pressable items within a ScrollView causing automatic snap to the top

Hi I'm working on a mobile application in react native. Its a simple app that lets you search for ingredients in a search bar.
I have a small bug which I can't seem to fix regarding the scrollview and setstate. I have a function that displays the search list under my search bar. It is an absolutely positioned element. The bug occurs when I try to scroll down on the scrollview and press on one of the items, instead of the scrollview remaining in place it scrolls directly to the top. Ideally I would like the scrollview to remain in place once the user has pressed on a item. I feel like it has something to do with how I'm calling setstate. The function is as follows:
const [userIngredients, setUserIngredients] = useState([]);
const OutputSearchList = () => {
const clickIngredient = (i) => {
if (!userIngredients.includes(i)) {
setUserIngredients((temp) => [...temp, i]);
} else {
const temp = userIngredients.filter((item) => item !== i);
setUserIngredients(temp);
}
};
return ingredients.map((item) => {
return (
<TouchableOpacity
style={styles.searchBarListItem}
onPress={() => clickIngredient(item)}
key={item}
>
<View style={styles.searchBarListContentChecked}>
<Text style={styles.searchBarListText}>{item}</Text>
<Ionicons
style={styles.searchBarListAdd}
name="checkmark-circle-outline"
size={28}
color="#000000"
/>
</View>
</TouchableOpacity>
);
});
};
and the function is called like so:
<ScrollView>
{ingredients?.length > 0 ? (
<View>
<OutputSearchList />
</View>
) : searchText?.length > 0 ? (
<View>
<Text>No ingredients found</Text>
</View>
) : (
<View>
<Text>Search for an ingredient (e.g. Eggs, Beef, Rice)</Text>
</View>
)}
</ScrollView>

React Native TextInput onFocus does not allow onPress of other child components

Nested TextInput component does not allow other components' onPress function to be called. Only when the TextInput is not focused, the onPress works fine.
React Native Version : 0.66.3
Here is my code
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClearSearchText}>
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})
Attached are the images of
Expected.
VS
The issue
When the cross icon is pressed on focused state, the textInput is unfocused rather What I am trying to achieve is that the search text gets cleared & the input remains focused.
Note: The onPress works perfectly fine when input is not focused
Any help is appreciated. Thanks!
PS: Tried TouchableOpacity & also I have tried wrapping the components inside a ScrollView to use keyboardShouldPersistTaps='handled' as mentioned in one of the SO answer but to no success.
Found a workaround to this is to wrap the whole component into a ScrollView and adding the prop keyboardShouldPersistTaps='handled'
Previously I was making the View inside the Component as ScrollView and adding keyboardShouldPersistTaps='handled' which did not work
export const Component = (props): JSX.Element {
...
return (
<ScrollView contentContainerStyle={styles.searchBoxContainer}
keyboardShouldPersistTaps='handled'>
...
</ScrollView>
)
})
The key was to wrap the entire component inside the ScrollView,
Here's what worked:
<ScrollView keyboardShouldPersistTaps='handled'>
<Component {...props}/>
</ScrollView>
Guess this was a silly mistake, but worth pointing out!
You're setting the focus of the entire component based on whether the TextInput has focus. Since the clear button is outside the text input, pressing it causes the component to lose focus.
One solution is to store the TextInput instance in a ref. When the clear button is pressed, you can refocus the text input. I've copied your component below and added some new lines, which are marked in comments.
export const Component = (props): JSX.Element {
const { searchText, onChangeSearchText, onClearSearchText } = props
const textInputRef = useRef(null); // new
const [searchViewFocused, setSearchViewFocused] = useState<boolean>(false)
const searchIcon = searchViewFocused ? "searchActive" : "searchInactive"
const cancelIcon = searchViewFocused ? "cancelActive" : "cancelInactive"
const onClear = () => {
onClearSearchText();
textInputRef.current?.focus();
} // new
return (
<View style={styles.searchBoxContainer}>
<View style={[styles.searchBox, searchViewFocused && styles.searchBarActive]}>
<Icon styles={styles.searchIcon} icon={searchIcon} />
<TextInput
ref={textInputRef} // new
style={styles.searchInput}
onChangeText={onChangeSearchText}
value={searchText}
onFocus={() => setSearchViewFocused(true)}
onBlur={() => setSearchViewFocused(false)}
autoCompleteType={"off"}
numberOfLines={1}
/>
{searchText !== "" && (
<Pressable style={styles.clearIcon} onPress={onClear}> // calls new function
<Icon icon={cancelIcon} />
</Pressable>
)}
</View>
</View>
)
})

onPress of TouchableOpacity gets called when loading Flatlist

I have a flatlist with a search function. In the next step, I want something to happen when I press within the item. I'm facing the problem that the TouchableOpacity is visible, but nothing happens when it's pressed. I've tried the same with a Button and face the same issue.
Instead of onPress being called when something is pressed, it somehow get's called once the screen loads immediately. If I for example console.log(item.title) I get all the titles in my console log that are currently in the flatlist.
I've tried to figure out what is causing this for many hours, but can't seem to find any reason. Any help is highly appreciated.
I have a Flatlist that is populated with data, set up as follows:
return (
<View style={styles.list}>
<FlatList
data = {this.state.data}
renderItem={renderListItem}
keyExtractor={item => item.id}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
const renderListItem = (item) => {
return (
<MyTouchable
id={item.item.id}
title={item.item.title}
/>
);
}
MyTouchable Component looks like this:
<View>
<TouchableOpacity onPress={console.log("Pressed")}>
<View style={styles.mainView}>
<View>
<Text style={styles.text}>{props.id} {props.title}</Text>
</View>
</View>
</TouchableOpacity>
</View>
Try to pass the console.log inside an arrow function
<TouchableOpacity onPress={() => console.log("Pressed")}>
...
</TouchableOpacity>
You can’t write like this: <Component makeThing={myFunc()} />. You should write like that: <Component makeThing={() => myFunc()} /> if you are not using useCallback.
Make sure to read the docs about passing functions to components.
You must provide and arrow function, and call your function inside it.
Or just use useCallback hook:
const Component = () => {
const myFunction = useCallback(() => {
// do something
}, []);
return <AnotherComponent coolFunction={myFunction} />
}

InfiniteScroll using ScrollView - React Native

I have a list using the ScrollView of react native itself. Basically, I build a list dynamically through an API return.
async fetchData(userSearch) {
const {route} = this.props;
const {params} = route;
const {type} = params;
this.setState({
loading: true,
});
const responseProcedures = await scheduleResource.getProcedures(userSearch);
this.setState({
procedures: responseProcedures.data,
loading: false,
});
}
<ScrollView
onScroll={(event) => this.shouldLoadMoreContent(event)}
>
{procedures.map(procedure => (
<ArrowBox key={procedure.id} onPress={() => RootNavigation.navigate('ProcedureDetails', {procedure})}>
<Text bold style={styles.ProcedureTitle}>
{procedure.name}
</Text>
{!!procedure.synonyms.length && (
<>
<Text bold style={styles.ProcedureSynonymTitle}>
Sinônimos
</Text>
<View style={styles.ProcedureSynonymOptionsContainer}>
{procedure.synonyms.map(synonym => <Text style={styles.ProcedureSynonymOption} key={synonym}>{synonym}</Text>)}
</View>
</>
)}
</ArrowBox>
))}
</ScrollView>
The problem is that I load the entire return from the API and it slows down.
I would like to know how to dynamically load the content and make new calls in the api, when I reach the end of the page.
Api allows me to place offset and limit.
Could someone give me some example?
Thanks!!!!!
Basically the ScrollView is not designed to handle dynamic data, the correct component that is designed to perform this function is called Flatlist. It works almost exactly like ScrollView but it is faster and will only render components that are shown on the screen.
Please import Flatlist from React Native like this...
//At the top of your file, please import FlatList together with all the modules that you want
import { FlatList, Text, View } from "react-native";
Then replace the entire ScrollView in your code with a Flatlist like this:
<FlatList
keyExtractor={(procedure) => procedure.id}
data={this.state.procedures}
renderItem={(procedure) => {
return (
<ArrowBox
key={procedure.id}
onPress={() =>
RootNavigation.navigate("ProcedureDetails", {
procedure })}>
<Text bold style={styles.ProcedureTitle}>
{procedure.name}
</Text>
{!!procedure.synonyms.length && (
<>
<Text bold style={styles.ProcedureSynonymTitle}>
Sinônimos
</Text>
<View
style={styles.ProcedureSynonymOptionsContainer}>
{procedure.synonyms.map((synonym) => (
<Text
style={styles.ProcedureSynonymOption}
key={synonym}>
{synonym}
</Text>
))}
</View>
</>
)}
</ArrowBox>
);
}}
></FlatList>;

Resources