I want to update state of key heart in the array's objects when the heart icon pressed it changes to red so for this I'm using react native icons and i'm using heart and hearto to switch when click on it
here is the code:
state = {
localAdversiment: [
{
title: "Ecloninear 871",
image: require("../../assets/images/truck_image.png"),
year: "2015",
type: "Truck",
status: "new",
price: "$ 2000",
heart: "hearto"
}
Here it function which is called when heart icon pressed
handleFavourite = index => {
const { heart } = this.state.localAdversiment[index];
this.setState(
{
heart: "heart"
}
);
};
here is the heart icon code
<TouchableOpacity onPress={() => this.handleFavourite(index)}>
<Icon
name={item.heart}
type={"AntDesign"}
style={{ fontSize: 18 }}
/>
</TouchableOpacity>
kindly help me how to update heart as heart instead of hearto when clicked
You can do it easily by following approach
state = {
localAdversiment: [
{
id: 0,
title: "Ecloninear 871",
image: require("../../assets/images/truck_image.png"),
year: "2015",
type: "Truck",
status: "new",
price: "$ 2000",
heart: "hearto",
selected: false
}
}
now in onPress do this
handleFavourite = (item) => {
const { id } = item;
this.setState({
localAdvertisement: this.state.localAdvertisement.map((item) => {
if(item.id === id){
return {
...item,
selected: !item.selected
}
}
return item
})
})
};
Now render like this
<TouchableOpacity onPress={() => this.handleFavourite(item)}>
<Icon
name={item.selected ? "heart" : 'hearto'}
type={"AntDesign"}
style={{ fontSize: 18 }}
/>
</TouchableOpacity>
Hope it will help you
Edit this function as follows:
handleFavourite = index => {
let updatedlocalAdversimentStates = this.state.localAdversiment;
updatedlocalAdversimentStates[index].heart = "heart";
this.setState(
{
localAdversiment: updatedlocalAdversimentStates
}
);
};
Related
I'm receiving data from api like this:
{
"isTrue": true,
"data1": {
"username": "user1",
"images": [
"image1.jpg",
"image2.jpg"
]
},
"data2": {
"location": "new york",
"age": "80"
}
}
and setting it in my state as details.
I want to display data in flatlist, so I do this:
<FlatList
data={state.details}
renderItem={({item}) => {
<Details item={item} />;
}}
></FlatList>
in my component I render data like:
export default Details = ({item}) => {
return item
? Object.values(item).map(value => {
<Text>{value.data1?.username}</Text>;
})
: null;
};
Why don't the items render?
Make sure u pass Array to flat list
like :
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",
},
];
flat list will do for loop for you, so u don't need to values(item).map you can do:
export default Details = ({item}) => {
return
<View>
<Text>{item.isTrue}</Text>
<Text>{item.data1.username}</Text>
</View>
};
change
renderItem={({item}) => {
<Details item={item} />;
}}
to
renderItem={({item}) => {
return <Details item={item} />;
}}
or
renderItem={({item}) => (<Details item={item} />)}
finally don't forget to add <View></View> as parent for <Text><Text>
what I try to do is to have the same display as this picture :
So in my menu the plant type (Type of plant1) is displayed above a gray bar and when you click on the down chevron then you can see all the plants name, related to this type, with checkboxes on left, by default there will be all checked. And the blue rectangle indicates the number of plants that have been selected.
How can I do that, which package can help me in REACT?
Here my plants.json :
{
"plants_type": [
{
"_id_type": "1",
"name_type": "Type of plant1",
"plants": [
{
"name": "Plant1.1",
"_id": "2"
},
{
"name": "Plant1.2",
"_id": "3"
}
]
},
{
"_id_type": "4",
"name_type": "Type of plant2",
"plants": [
{
"name": "Plant2.1",
"_id": "5"
},
{
"name": "Plant2.2",
"_id": "6"
}
]
}
]
}
You can create a dropdown list on your own like below. I have added the logic of selecting items to the data itself.
You can keep a component called Category to keep a single state of the parent menu item. Whether it's open or not. Then iterate over the plants as checkbox inputs to make them selectable.
I have used a simple initialize function to make all the items selected initially. This should work as you expect. Add a console log of selectionMenu to see how selected property changes while toggling items.
Move the inline styles to CSS classes to make the code more clear.
const data = { plants_type: [ { _id_type: "1", name_type: "Type of plant1", plants: [ { name: "Plant1.1", _id: "2" }, { name: "Plant1.2", _id: "3" } ] }, { _id_type: "4", name_type: "Type of plant2", plants: [ { name: "Plant2.1", _id: "5" }, { name: "Plant2.2", _id: "6" } ] } ] };
const Category = ({ _id_type, name_type, plants, changeSelection }) => {
const [toggleState, setToggleState] = React.useState(false);
return (
<div key={_id_type}>
<div
style={{
cursor: "pointer",
userSelect: "none",
display: "flex",
margin: "2px",
backgroundColor: "lightgray"
}}
onClick={() => setToggleState((prev) => !prev)}
>
<div>{name_type}</div>
<div
style={{
backgroundColor: "blue",
color: "white",
padding: "0px 10px",
marginLeft: "auto"
}}
>
{plants.filter(({ selected }) => selected).length}
</div>
</div>
<div style={{ marginLeft: "10px" }}>
{toggleState &&
plants.map(({ name, _id, selected }) => (
<div key={_id}>
<input
key={_id}
type="checkbox"
value={name}
checked={selected}
onChange={(e) => changeSelection(_id_type, _id, e.target.value)}
/>
{name}
</div>
))}
</div>
</div>
);
};
const App = () => {
const initializeSelectionMenu = (data) => {
return data.map((item) => {
return {
...item,
plants: item.plants.map((plant) => ({ ...plant, selected: true }))
};
});
};
const [selectionMenu, setSelectionMenu] = React.useState(
initializeSelectionMenu(data.plants_type)
);
console.log(selectionMenu);
const changeSelection = (catId, itemId, value) => {
setSelectionMenu((prevSelectionMenu) =>
prevSelectionMenu.map((item) => {
if (item._id_type === catId) {
return {
...item,
plants: item.plants.map((plant) => {
if (plant._id === itemId) {
return { ...plant, selected: !plant.selected };
}
return plant;
})
};
}
return item;
})
);
};
return (
<div>
{selectionMenu.map((item) => (
<Category
{...item}
changeSelection={changeSelection}
key={item._id_type}
/>
))}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
I have record state in my react native app.
state{
record:[] //some data inside, When i console my state it looks like this:
}
Console output of my record state:
Array [
Object {
"name": "abc",
"age": 23,
},
]
Array[
Object {
"name": "xyz",
"age": 27,
},
]
When i render it through FlatList it shows only first item of array that is name abc and age 23. While it should also load 2 array item in state, which is name xyz and age 27. below is the code for output of state.
displaydata(){
firebase.firestore()
.collection('users').where('age', '>=', 21)
.get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
const urecords = [];
const udata = documentSnapshot.data();
urecords.push(udata);
this.setState({ record: [...urecords] })
});
});
}
}
render(){
return(
<View style={{ flex: 1 }}>
{this.state.record ? (
<>
<Text>Data from firebase firestore</Text>
<FlatList
style={{ flex: 1 }}
data={this.state.record}
keyExtractor={(key, index) => key + index}
renderItem={(itemData) => {
console.log(this.state.record); // it displays all data of state in console as i have consoled above
return <Text>{itemData.item.name}{itemData.item.age}</Text>; // it displays first array data(item) only, which is abc and 23
}
}
/>
</>
) : (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<ActivityIndicator size="large" color="black" />
</View>
)}
</View>
);
}
I want to load complete state on my screen.
It happens because you have 2 different arrays inside this.state.record.
Try to spread your data arrays inside state or combine them into 1 union array. Your this.state.record should look like this
state = {
records: [
{ name: 'xyz', age: '23', },
{ name: 'abc', age: '27', },
]
This will show you list with 2 objects
console.log('STATE RECORDS', this.state.records)
// console.log output
STATE RECORDS [
{ name: 'xyz', age: '23', },
{ name: 'abc', age: '27', },
]
I have a Product Options "Color, Size, etc" And as we know user can select one thing from the option "selected just red color from Colors", in this time I ad the selected one the separate Array "All Option user selected" but the issue is the user can add duplicated options in the same filed "e.g. Color" So how can I solve this issue?
The final Thing should be: One thing from separate Option
For Example
SelectedOptions = [
{ name:"red",id:88,optionType:"Color"},
{ name:"XL",id:22,optionType:"Size"},
....
]
But What I go now
SelectedOptions = [
{ name:"red",id:88,optionType:"Color"},
{ name:"green",id:87,optionType:"Color"},
{ name:"XL",id:22,optionType:"Size"},
{ name:"M",id:22,optionType:"Size"},
....
];
I know that's because I push any selected one to the SelectedOptions Array,
I'm trying to solve it by checking the optionType but I did not get any good idea
Code snippet
const [selectedIndexColor, setSelectedIndexColor] = useState<
number | undefined
>();
const [selectedIndexText, setSelectedIndexText] = useState<number | null>();
const [selectedIndexImage, setSelectedIndexImage] = useState<number | null>();
interface ManipulateValueOptionProp extends valueOptionProp {
optionType: string;
}
const [allOptions, setAllOptions] = useState<ManipulateValueOptionProp[]>([]);
const renderValue = (value: valueOptionProp, type: string) => {
const selectedColor = selectedIndexColor === value.id;
const selectedText = selectedIndexText === value.id;
const selectedImage = selectedIndexImage === value.id;
switch (type) {
case 'text': {
return (
<View
style={[
styles.selectedText,
{backgroundColor: selectedText ? 'black' : 'transparent'},
]}>
<Text
style={{
textAlign: 'center',
color: selectedText ? 'white' : 'black',
fontSize: 12,
}}>
{value.name_en}
</Text>
</View>
);
}
case 'Color': {
return (
<>
<View
// #ts-ignore
// eslint-disable-next-line react-native/no-inline-styles
style={{
width: 53,
height: 53,
backgroundColor: value.display_value,
}}
/>
{selectedColor ? (
<View style={styles.selectedColor}>
<CheckmarkIcon color="black" />
</View>
) : null}
</>
);
}
case 'images': {
return (
<>
<Image
// #ts-ignore
source={{uri: value.display_value}}
// eslint-disable-next-line react-native/no-inline-styles
style={{width: 53, height: 53, backgroundColor: '#0f4c7f'}}
/>
{selectedImage ? (
<View style={styles.selectedColor}>
<CheckmarkIcon />
</View>
) : null}
</>
);
}
default: {
return null;
}
}
};
{item.options.map((option) => {
return (
<View style={styles.optionsBox}>
<Text style={styles.optionTxt}>{option.label_en}</Text>
<View style={{flexDirection: 'row'}}>
{option.values.map((value: valueOptionProp) => {
return (
<ScalePressable
key={`${option.id}${value.id}`}
onPress={() => {
option.type === 'Color' &&
setSelectedIndexColor(value.id);
option.type === 'text' && setSelectedIndexText(value.id);
option.type === 'images' &&
setSelectedIndexImage(value.id);
if (
!allOptions.some(
(alreadyExist) => alreadyExist.id === value.id,
)
) {
setAllOptions((options) => [
...options,
{...value, optionType: option.type},
]);
}
}}>
<View style={styles.values}>
{renderValue(value, option.type)}
</View>
</ScalePressable>
);
})}
</View>
</View>
);
})}
Here is one possible solution. You may consider creating a new array by removing all options with the same option type as the new option and then adding the new option into the new array.
let selectedOptions = [
{ name: 'red', id: 88, optionType: 'Color' },
{ name: 'XL', id: 22, optionType: 'Size' },
];
let newOption = { name: 'green', id: 87, optionType: 'Color' };
selectedOptions = [
...selectedOptions.filter(
option => option.optionType != newOption.optionType
),
newOption,
];
Seems to me you just need to remove deselected options from allOptions array when the user presses that same filter option.
onPress={() => {
option.type === 'Color' && setSelectedIndexColor(value.id);
option.type === 'text' && setSelectedIndexText(value.id);
option.type === 'images' && setSelectedIndexImage(value.id);
if (allOptions.some(option => option.type === value.type)) {
setAllOptions(options => options.filter(option => option.type !== value.type));
} else {
setAllOptions((options) => [
...options,
{ ...value, optionType: option.type },
]);
}
}}
My English is not very good, sorry for that. There is a structure that I want to make multiple data entries. I will add separate json lines for each input. But I can add once from the same line. But I want to create a separate json data for each input. I am sharing the sample code. It doesn't work that way because it constantly updates the previous data in.
var families = [];
for(let i = 0; i < formStep + 1; i++) {
families.push(
<View key={i}>
<View>
<Text style={{ marginBottom: 5 }}>T.C</Text>
<Input
placeholder='Lütfen T.C belirtin'
style={{ marginBottom: 10 }}
onChangeText={(input) => this.setState(prevState => ({
formData: [...prevState.formData, {tc: input}]
}))}
/>
</View>
<View>
<Text style={{ marginBottom: 5 }}>İsim</Text>
<Input
placeholder='Lütfen ad ve soyad belirtin'
style={{ marginBottom: 10 }}
/>
</View>
<View>
<Text style={{ marginBottom: 5 }}>Meslek</Text>
<Input
placeholder='Lütfen meslek belirtin'
style={{ marginBottom: 10 }}
/>
</View>
{(formStep > 0) ? <Divider style={{marginBottom: 15, marginTop: 10}}></Divider> : null}
</View>
)
}
working input onChangeText method;
Array [
Object {
"tc": "0",
},
]
Array [
Object {
"tc": "0",
},
Object {
"tc": "00",
},
]
Array [
Object {
"tc": "0",
},
Object {
"tc": "00",
},
Object {
"tc": "000",
},
]
But I want;
Array [
Object {
"tc": "000",
},
]
And then if there is more than one input;
Array [
Object {
"tc": "000",
},
Object {
"tc": "111",
},
Object {
"tc": "222",
},
]
I hope I could tell. Thanks for your help in advance.
If I understand what you want, you just need to overwrite the field you want to update this way:
onChangeText={(input) => this.setState(prevState => ({
formData: [...prevState.formData.tc, {tc: input}]
}))}
And for the other inputs, it would look something like this:
onChangeText={(input) => this.setState(prevState => ({
formData: [...prevState.formData.exemple, {exemple: input}]
}))}
You can also group input changes in one function:
updateText = (key, value) => {
// Merge the old key, or set it
this.setState(currentState => ({
formData: [
...currentState.formData,
[key]: value
]
}));
};
And you use it that way:
onChangeText={text => this.updateText("tc", text)}