the flatList after deleting work but not displayed on Screen items does't change
const App = () => {
const data = [
{ id: 1, text: "item One" },
{ id: 2, text: "item Two" },
{ id: 3, text: "item Three" },
{ id: 4, text: "item Four" },
];
const [state, setState] = useState(data);
const onPressItem = (id) => {
// code de delete item
const data = state;
alert(id);
const filterrArray = data.filter((val, i) => {
if (val.id !== id) {
return val;
}
});
console.log("filteerArray " , filterrArray)
setState( filterrArray)
};
const renderItem = ({ item }) => {
return (
<TouchableOpacity style={styles.item}>
<Text style={styles.text}>{item.text}</Text>
<Button title="Supprimer" onPress={() => onPressItem(item.id)} />
</TouchableOpacity>
);
};
const handleCheck = () => {
console.log('__________________________')
console.log(state)
}
return (
<View style={{ flex: 1, padding: 0, marginTop: "10%" }}>
<SafeAreaView>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
</SafeAreaView>
<Button
title = "Verifier state"
onPress={handleCheck}
/>
</View>
);
};
i try the console log every time before the deleting and after the deleting is work fine but doest change on Screen or refresh automatically i dont know
not sure if I got your question right but if you want to update your flatlist, you need to pass state to data.
data={state}
Related
I have flatlist horizontal like below
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad353abb28ba',
title: 'Fourth Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd291aa97f63',
title: 'Fifth Item',
},
{
id: '58694a0f-3da1-471f-bd961-145571e29d72',
title: 'Sixth Item',
},
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<FlatList
horizontal
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
Whenever Item entered the viewport , I want to add animation to that element.I can get X and Y position of scroll with onScroll , now how do i get the positions of items to check if its in view port or if it went away from viewport...
Thank you.
Sorry for the late response. My pc has been super weird lately so when I encounter errors I have to second guess myself, and when nothing appears wrong, I second guess my pc (this time it was entirely me).
Here's my answer. I implemented the basic fade in/out [animation example][1] into the Item component. Whether it fades out or in is decided by the prop isViewable
// Item.js
const Item = (props) => {
const {
item:{title, isViewable}
} = props
/*
I copied and pasted the basic animation example from the react-native dev page
*/
const fadeAnim = useRef(new Animated.Value(1)).current;
const fadeIn = () => {
Animated.timing(fadeAnim, {
toValue: 1,
duration: 1000,
useNativeDriver:false
}).start();
};
const fadeOut = () => {
Animated.timing(fadeAnim, {
toValue: 0,
duration: 1500,
useNativeDriver:false
}).start();
};
/* end of animation example*/
// fade in/out base on if isViewable
if(isViewable || isViewable == 0)
fadeIn()
else
fadeOut()
const animation = {opacity:fadeAnim}
return (
//add animation to Animated.View
<Animated.View style={[style.itemContainer,animation]}>
<View style={style.item}>
<Text style={style.title}>{title}</Text>
</View>
</Animated.View>
);
}
Create a FlatListWrapper (to avoid the onViewableItemChange on fly error). By doing this, as long as you don't make changes to FlatListWrapper, you wont get the on the fly error
// FlatListWrapper.js
const FlatListWrapper = (props) => {
// useRef to avoid onViewableItemsChange on fly error
const viewabilityConfig = useRef({
// useRef to try to counter the view rerender thing
itemVisiblePercentThreshold:80
}).current;
// wrapped handleViewChange in useCallback to try to handle the onViewableItemsChange on fly error
const onViewChange = useCallback(props.onViewableItemsChanged,[])
return (
<View style={style.flatlistContainer}>
<FlatList
{...props}
horizontal={true}
onViewableItemsChanged={onViewChange}
/>
</View>
);
}
const style = StyleSheet.create({
flatlistContainer:{
borderWidth:1,
borderColor:'red',
width:'50%',
height:40
},
// main FlatList component
const FlatListAnimation = () => {
// store the indices of the viewableItmes
const [ viewableItemsIndices, setViewableItemsIndices ] = useState([]);
return (
<SafeAreaView style={style.container}>
<FlatListWrapper
horizontal={true}
//{/*give each data item an isViewable prop*/}
data={DATA.map((item,i)=>{
item.isViewable=viewableItemsIndices.find(ix=>ix == i)
return item
})}
renderItem={item=><Item {...item}/>}
keyExtractor={item => item.id}
onViewableItemsChanged={({viewableItems, changed})=>{
// set viewableItemIndices to the indices when view change
setViewableItemsIndices(viewableItems.map(item=>item.index))
}}
//{/*config that decides when an item is viewable*/}
viewabilityConfig={{itemVisiblePercentThreshold:80}}
extraData={viewableItemsIndices}
/>
{/* Extra stuff that just tells you what items should be visible*/}
<Text>Items that should be visible:</Text>
{viewableItemsIndices.map(i=><Text> {DATA[i].title}</Text>)}
</SafeAreaView>
);
}
const style = StyleSheet.create({
container:{
padding:10,
alignItems:'center'
},
flatlistContainer:{
borderWidth:1,
borderColor:'red',
width:'50%',
height:40
},
item:{
borderWidth:1,
padding:5,
},
itemContainer:{
padding:5,
}
})
By wrapping your FlatList in a separate file, you wont encounter the "onViewableItemsChange on the fly" error as long as you dont modify FlatListWrapper.js
[1]: https://reactnative.dev/docs/animated
Use onViewableItemsChanged this is called when the items in the flatlist changes.
const handleViewableItemsChanged = (viewableItems, changed) => {}
<Flatlist
...
onViewableItemsChanged={handleViewableItemsChanged}
I have been trying to delete a list when pressing the button, but it does not work at all. I know I should use value.id !== id, so I did, but pretty not so sure if the way I tried is correct.
Here is the code I tried.
import React, { useState } from 'react';
const cartData = [
{
id: 0,
store: 'Zaful',
productImage:
'https://gloimg.zafcdn.com/zaful/pdm-product-pic/Clothing/2021/01/20/thumb-img/1612378696788831740.jpg',
productName: 'Jacket',
optColor: 'black',
optSize: 'S',
price: 50000,
},
{
id: 1,
store: 'Zaful',
productImage:
'https://gloimg.zafcdn.com/zaful/pdm-product-pic/Clothing/2020/09/28/goods-img/1603157669032643775.jpg',
productName: 'Padded Jacket',
optColor: 'Blue',
optSize: 'S',
price: 35000,
},
];
const PaymentCart = ({ selectedNum, totalNum }) => {
const navigation = useNavigation();
const [cart, setCart] = useState(cartData);
const [isChecked, setIsChecked] = useState([]);
const isAllChecked = isChecked.length === cartData.length;
const setIsAllChecked = () => {
setIsChecked(isAllChecked ? [] : [...cartData.map((item) => item.id)]);
};
const handleChecked = (id) => {
setIsChecked((prevState) => {
const index = prevState.indexOf(id);
if (index === -1) {
return [...prevState, id];
} else {
const tempArr = [...prevState];
tempArr.splice(index, 1);
return [...tempArr];
}
});
};
// This is the function I want to fix
const onRemove = (id) => {
console.log(id);
const newCart = cart.filter((value) => value.id !== id);
setCart(newCart);
};
return (
<View style={[styles.container]}>
{cartData?.length > 0 ? (
<>
<ScrollView>
<CheckBoxSet
isChecked={isAllChecked}
setIsChecked={setIsAllChecked}
checkBoxText={'Select All (2/3)'}
deletedText={'Delete Selected'}
/>
<View style={[styles.contentBox]}>
<Text style={[styles.storeName]}>{cartData[0].store}</Text>
{cartData.map((item, index) => (
<View key={item.id} style={{ marginBottom: 30 }}>
<CheckBoxSet
isChecked={isChecked.includes(item.id)}
setIsChecked={() => handleChecked(item.id)}
checkBoxText={'Select'}
deletedText={'Delete'}
checkBoxTextStyle={[styles.checkBoxText]}
containerStyle={{ marginBottom: 13 }}
// This is what I want to fix
deleteOnPress={() => onRemove(item.id)}
/>
<ProductInfoBox
price={item.price}
productImage={{
uri: item.productImage,
}}
productName={item.productName}
optColor={item.optColor}
optSize={item.optSize}
/>
</View>
))}
</View>
</ScrollView>
</>
) : (
<View style={[styles.noProductsContainer]}>
<Text style={[styles.noProducts]}>장바구니에 상품이 없어요.</Text>
</View>
)}
</View>
);
};
export default PaymentCart;
I have no idea what I have done wrong. Perhaps is it related to setIsAllChecked? Should I use that too?
You should map on cart not cartData:
because onRemove modifies cart
{cart.map((item, index) => (
I need a little help trying to figure this out. I am using react native elements flatlist with a checkbox inside of it. I am also using react hooks with this. Everything is working perfectly but when I try and select one of the items in the checkbox it selects all of the items. Now I have had this issue before when I was just using components and not hooks and functions. I tried to use the same method that I used here Selecting multiple items
Like this...
function ViewCategoryWS2({navigation}) {
const {category, setCategory} = useContext(ItemContext);
const [eats, setEats] = useState([]);
const [checked, toggleChecked] = useState(false);
function back() {
navigation.navigate('MenuWS2');
}
function test(index) {
const foods = category;
foods[index].checked = !foods[index].checked;
setCategory(foods);
}
return (
<View style={styles.container}>
<Icon
name='arrow-left'
color="#000000"
size={25}
style={styles.menuIcon}
onPress={back}
/>
<FlatList
data={category}
//extraData={eats}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<CheckBox
center
titleProps={{ color: 'black', fontWeight: 'bold'}}
title={item}
iconRight
checked={checked}
onPress={() => test(index)}
size={30}
containerStyle={styles.checkBox}
/>
)}
/>
</View>
)
}
and I keep getting this error TypeError: Attempted to assign to readonly property. I have also tried it this way...
<FlatList
data={category}
//extraData={eats}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<CheckBox
center
titleProps={{ color: 'black', fontWeight: 'bold'}}
title={item}
iconRight
checked={checked}
onPress={() => toggleChecked(!checked)}
size={30}
containerStyle={styles.checkBox}
/>
)}
/>
Here is my code from where the context is coming from. This page I pull data from my datbase and it displays categories. I click on any category and it pulls data from my database that's assigned to that certain category that was clicked on..
Here is the code...
import ItemContext from '../context/CategoryItems';
export default function menuWS({navigation}) {
const [restaurantlocationcode, setRestaurantlocationcode] = useState('')
const [menu, setMenu] = useState([]);
const {category, setCategory} = useContext(ItemContext);
const [selected, setSelected] = useState(0);
function viewMenu() {
fetch('URL', {
method: 'POST',
body: JSON.stringify({ restaurantlocationcode: restaurantlocationcode}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(response=> setMenu(response));
console.log(menu);
alert(menu);
}
function viewCategory({item}) {
fetch('URL', {
method: 'POST',
body: JSON.stringify({
category: item,
restaurantlocationcode: restaurantlocationcode,
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
})
.then(response => response.json())
.then(response => {
setCategory(response);
console.log(response);
alert(response);
});
navigation.navigate('ViewCategoryWS2', {category});
}
function showMenu() {
console.log(menu);
alert(menu);
}
const buttons = ['Menu']
return (
<View style={styles.container}>
<Input
style={styles.Input}
placeholder='Restaurant Location Code'
leftIcon={
<Icon
name='location-arrow'
size={24}
color='black'
/>
}
onChangeText={setRestaurantlocationcode}
value={restaurantlocationcode}
underlineColorAndroid='transparent'
/>
<ButtonGroup
onPress={viewMenu}
selectedIndex={selected}
selectedButtonStyle={{backgroundColor: 'blue'}}
buttons={buttons}
containerStyle={styles.buttonGroup}
/>
<FlatList
data={menu}
extraData={category}
keyExtractor={(item, index) => index.toString()}
renderItem={({item, index}) => (
<ListItem
titleStyle={{ color: 'black', fontWeight: 'bold'}}
title={item}
onPress={() => viewCategory({item})}
bottomDivider
chevron
/>
)}
/>
</View>
)
}
Here is my useContext code...
import { createContext } from 'react';
const ItemContext = createContext({});
export default ItemContext;
Here is the second part to my useContext code..
import React, {useState} from 'react';
import ItemContext from './CategoryItems';
const MenuItemState = ({children}) => {
const [category, setCategory] = useState([]);
return (
<ItemContext.Provider value={{category, setCategory}}>
{children}
</ItemContext.Provider>
)
}
export default MenuItemState;
And it just selects all of the items. I'm not sure what I am missing. Help with this would be greatly appreciated.
App Output:
import React, { useState } from 'react';
import { Text, View, StyleSheet, CheckBox, Icon, FlatList } from 'react-native';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
/*
I am using this data, but you can continue
with the one you getting from context
*/
const data = [
{ id: 1, title: 'one', checked: true },
{ id: 2, title: 'two', checked: false },
{ id: 3, title: 'three', checked: false },
{ id: 4, title: 'four', checked: false },
{ id: 5, title: 'five', checked: false },
{ id: 6, title: 'six', checked: false },
];
export default function App() {
const [category, setCategory] = useState(data);
const [eats, setEats] = useState([]);
const [checked, toggleChecked] = useState(false);
function back() {
// navigation.navigate('MenuWS2');
}
function test(index) {
/*
Use this approach while changing the state.
This will create the copy of original array,
and you can perform mutation there
and update state with it.
*/
console.log(index);
const foods = [...category];
foods[index].checked = !foods[index].checked;
setCategory(foods);
}
/*
In your Checkbox component,
use "onChange" prop instead of "onPress"
and "value" instead of "checked"
*/
return (
<View style={styles.container}>
<FlatList
data={category}
//extraData={eats}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<Card style={{ padding: 10, margin: 5 }}>
<Text>{item.title}</Text>
<CheckBox
center
titleProps={{ color: 'black', fontWeight: 'bold' }}
title={item}
iconRight
value={item?.checked}
onChange={() => test(index)}
size={30}
containerStyle={styles.checkBox}
/>
</Card>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 24,
backgroundColor: 'grey',
flex: 1,
},
});
Working Example: Expo Snack
Hi I'm trying to make a "like" system as you can see on instagram -> when i press the heart it becomes red and full, and if I press it again it becomes again black and with outline. When I Press one heart other must stay with their actual style
, but I'm encountering this error. : initializeAnArray is not a function... Please can you help me.
If maybe you have a better way to code what i'am trying to do I don't refuse your tips. Thank You
const data = [
{
id: "1",
message: "Hi",
},
{
id: "2",
message: "Hello",
},
{
id: "3",
message: "Welcome",
},
];
function Heart(props) {
const [dataUser, setDataUser] = useState(data);
const [heart, setHeart] = useState(initializeAnArray("heart-outline"));
const [heartColor, setHeartColor] = useState(initializeAnArray("black"));
const [getIndex, setGetIndex] = useState(-1);
const initializeAnArray = (value) => {
let newArray = [];
for (let i = 0; i < dataUser.length; i++) {
newArray.push(value);
}
return newArray;
};
const editArray = (array, id, value) => {
array[id] = value;
return array;
};
const heartPress = (id) => {
setGetIndex(id);
if ((id = getIndex)) {
heartColor[id] === "red"
? setHeartColor(editArray(heartColor, id, "black")) +
setHeart(editArray(heart, id, "heart-outline"))
: setHeartColor(editArray(heartColor, id, "red")) +
setHeart(editArray(heart, id, "heart-outline"));
}
setHeartColor(editArray(heartColor, id, heartColor[id]));
setHeart(editArray(heart, id, heart[id]));
};
return (
<Screen>
<FlatList
data={dataUser}
extraData={dataUser}
renderItem={({ item }) => (
<View style={styles.container}>
<View style={styles.message}>
<Text>{item.message}</Text>
<TouchableOpacity onPress={heartPress(parseInt(item.id) - 1)}>
<MaterialCommunityIcons
name={heart[parseInt(item.id) - 1]}
size={12}
color={heartColor[parseInt(item.id) - 1]}
/>
</TouchableOpacity>
</View>
</View>
)}
/>
</Screen>
);
}
const styles = StyleSheet.create({
container: {
alignItems: "center",
},
message: {
flexDirection: "row",
marginBottom: 20,
},
});
export default Heart;
can you add keyExtractor={item => item.id} to your component FlatList and try again
something like this:
<FlatList
data={dataUser}
extraData={dataUser}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.container}>
<View style={styles.message}>
<Text>{item.message}</Text>
<TouchableOpacity onPress={heartPress(parseInt(item.id) - 1)}>
<MaterialCommunityIcons
name={heart[parseInt(item.id) - 1]}
size={12}
color={heartColor[parseInt(item.id) - 1]}
/>
</TouchableOpacity>
</View>
</View>
)}
/>
https://reactnative.dev/docs/flatlist
im trying to refresh my flatlist from some page without going back to the principal menu, but it doesnt work.
I've already readed about extraData, but it doesnt work either.
Basiclly my program is like that:
I have a page called "passwords" and i add some passwords there from another page called "add passwords". When i click to add a password, i want to refresh the flatlist from the page "passwords" to show me the password that i just added.
This is my code from the page "add passwords"
...
state = {
arr: [],
local: '',
password: '',
obj: {
local: '',
password: ''
},
count: 1,
texto: ''
};
componentDidMount() {
//Here is the Trick
const { navigation } = this.props;
//Adding an event listner om focus
//So whenever the screen will have focus it will set the state to zero
this.focusListener = navigation.addListener('didFocus', () => {
this.setState({ count: 0 });
});
}
storeItem(item) {
try {
//we want to wait for the Promise returned by AsyncStorage.setItem()
//to be resolved to the actual value before returning the value~
console.log(item)
var joined = this.state.arr.concat(item);
console.log(joined)
this.setState({ arr: joined })
AsyncStorage.setItem('array', JSON.stringify(joined));
console.log(this.state.arr)
} catch (error) {
console.log(error.message);
}
}
componentWillMount() {
AsyncStorage.getItem('array').then(array => {
item = JSON.parse(array)
array ? this.setState({ arr: item }) : null;
console.log(item)
})
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={(text) => this.setState({ local: text })}
value={this.state.local}
/>
<TextInput
secureTextEntry={true}
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={(text) => this.setState({ password: text })}
value={this.state.password}
/>
<Button title='Adicionar'
onPress={() => this.storeItem({ local: this.state.local, password: this.state.password }) + alert("Adicionado com sucesso!") + this.props.navigation.navigate('Passwords')}
></Button>
</View>
);
}
}
And this is my page "passwords" where i want to refresh
componentWillMount() {
const { navigation } = this.props;
this.willFocusListener = navigation.addListener(
'willFocus',
() => {
this.setState({ count: 10 })
}
)
AsyncStorage.getItem('array').then(array => {
item = JSON.parse(array)
item ? this.setState({ arr: item }) : null;
console.log(this.state.arr)
})
}
renderItem = ({ item }) => (
<View style={{ flexDirection: 'row' }} style={styles.passwordContainer}>
<Text> {item.local} </Text>
<Text> {item.password} </Text>
</View>
)
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.arr}
renderItem={this.renderItem}
extraData={this.state} //this is what i tryied
/>
</View>
);
You can use your listener to update the state.
componentWillMount() {
this.willFocusListener = navigation.addListener(
'willFocus',
() => this.updateData()
}
updateData = () => {
this.setState({ count: 10 });
AsyncStorage.getItem('array').then(array => {
item = JSON.parse(array)
item ? this.setState({ arr: item }) : null;
console.log(this.state.arr)
});
}
Any state changes will rerender items.