React native while adding one item id by onpress it adds all the item at once - react-native

can anyone tell me what can i do..i want to change the add button to remove button when one item added and again onpress remove ...add button will come..
function //
const [multipletest, setmultipleTest] = React.useState([]);
function addTest(crypto) {
setmultipleTest((state) => [...state, crypto.id]);}
map list //
{filterdData.map((crypto, index) => (
<View key={index.toString()}>
<TouchableOpacity onPress={() => addTest(crypto)}>
{console.log(crypto, "crypto")}
<Text> Add</Text>
</TouchableOpacity>
</View>

This logic might help
function Example() {
// default state
const [multipletest, setmultipleTest] = React.useState([]);
const add = (crypto) => {
let newData = [...multipletest];
newData.push(crypto.id);
setmultipleTest(newData);
}
const remove = (crypto) => {
let newData = [...multipletest];
newData = newData.filter((e) => e !== crypto.id);
setmultipleTest(newData);
}
// map list
return filterdData.map((crypto, index) => {
// check crypto id already exist or not
const exists = multipletest.includes(crypto.id);
return (
<View key={index.toString()}>
<TouchableOpacity
onPress={() => {
// handle onpress either add or remove as per condition
exists ? remove(crypto) : add(crypto);
}}
>
<Text>{exists ? "Remove" : "Add"}</Text>
</TouchableOpacity>
</View>
);
});
}

Related

Call a function once onPress then display other function

I'm doing a react-native school project and i'm willing to know how to call a function on first press then display another function on other clicks :
<TouchableOpacity style={styles.btnMiddle} onPress={() => buyFishes(1)}>
<View style={styles.fish}>
<Text style={styles.shptxt}>50</Text>
<Image style={styles.coin2}source={require("../../assets/img/coin.png")} />
</View>
</TouchableOpacity>
here is my button, in my project this button is displayed on the Shop Screen and I need it to cost 50 on the first press (to unlock it), then I want it to stop costing 50 and just call another function.
here is my function to buy an item
const buyFishes = (id) => {
fishes.map(fishes => {
if(fishes.id === id)
{
if(Gold >= fishes.cost)
{
setGold(Gold - fishes.cost);
}
}
if (Gold < fishes.cost)
{
onPress: () => Alert.alert("Not enough Gold Kiddo !");
}
}
);
};
Any Idea ?
Thanks
Just add a state to your component and use it to call the functions you want accordingly.
const [clicked,setClicked] = useState(false);
<TouchableOpacity style={styles.btnMiddle} onPress={onPressHandler}>
<View style={styles.fish}>
<Text style={styles.shptxt}>50</Text>
<Image style={styles.coin2}source={require("../../assets/img/coin.png")} />
</View>
</TouchableOpacity>
const onPressHandler = (id) => {
setClicked(true);
if(clicked)
{
// call second function
}
else
{
// call first function
}
};

Toggle a button selection on same and others in React (Javascript)?

I have a form with a question and 3 answers. Only one answer can be selected so I need to toggle each answer individually AND toggle between the 3.
I put an incoming array of objects into state on component load and iterate over that data. I add in a selected key to each object of the array with boolean which will be deleted before form submit.
Right now the behavior is that I'm able to toggle the same button but clicking another does change the previous selected but have to click again to select the new current. Obviously one crucial set is missing but not sure if I should set up a new state or if it can be done with the current config. Basically, the buttons should behave like checkboxes.
The code:
const answers = ['Frequency', 'Some Times', 'Hardly Ever'] // predefined
const ChecklistModal = ({ setShowModal, checklist }: any) => {
const [updatedList, setUpdatedList] = useState(
checklist.list.map((c) => ({
...c,
selected: !!c.answer, // added key with truthy value based on already chosen from
// backend or selected in form (frontend)
})),
)
// where the magic happens
const handleAnswer = (
answer: string,
questionId: number,
listIdx: number,
) => {
const listCopy = [...updatedList]
const list = listCopy[listIdx]
list.question = questionId
list.answer = answer
list.selected = !list.selected
listCopy[listIdx] = list
setUpdatedList(listCopy)
}
return (
<Modal>
<View style={[styles.container, containerByDevice]}>
// relevant code
{checklist.list.map((li, index) => (
<View key={li.question.id}>
<Text style={styles.questionText}>{li.question.title}</Text>
<View style={styles.answerRow}>
{answers.map((answer) => (
<View
key={answer}
style={
updatedList[index].selected &&
updatedList[index].answer === answer
? styles.selectedAnswerButton
: styles.answerButton
}
>
<TouchableOpacity
onPress={() => {
handleAnswer(answer, li.question.id, index)
}}
>
<Text>{answer}</Text>
</TouchableOpacity>
</View>
))}
</View>
</View>
))}
</View>
</Modal>
)
}
export default ChecklistModal
The initial checklist data looks like this:
checklist {
concern {
title
}
list {
question {
id
title
}
answer
}
}
}
}
`
You'll need to create another state which will store the selected answer and then add modify your condition like this: -
// state to store the selected answer
const [selectedAnswer, answer]= useState('');
// modify your condition
<View
key={answer}
style={
updatedList[index].selected &&
selectedAnswer == answer && // <== Add this condition
updatedList[index].answer === answer
? styles.selectedAnswerButton
: styles.answerButton
}
>
<TouchableOpacity
onPress={() => {
handleAnswer(answer, li.question.id, index)
}}
>
<Text>{answer}</Text>
</TouchableOpacity>
</View>
Also i have created a snack for your reference :- https://snack.expo.dev/#arjunshukla97/toggleanswer

Error in Nested map function React Native

I can't achieve to have two nested map with this below code i got [Error: Text strings must be rendered within a <Text> component.]
const MyScreen = ({ route, navigation }) => {
const { fieldsBlock } = route.params;
// Iterate
const fieldItems = fieldsBlock.map((fieldBlock) => (
<View>
<Text>{fieldBlock.title}</Text>
{fieldBlock.fields.map((field) => (
<Text>{field.fieldValue}</Text>
))}
</View>
)
);
return (
<View>
{fieldItems}
</View>
);
};
Only if i use one map function then it works but with the nested map function it give an error.
I think, that the problem is that if fieldItems results in an empty array, you will be trying to render nothing between View tags.
I suggest to change your code to render null if arrays are empty, like this
const MyScreen = ({ route, navigation }) => {
const { fieldsBlock } = route.params;
// Iterate
const fieldItems = fieldsBlock.map((fieldBlock) => (
<View>
<Text>{fieldBlock.title}</Text> // <-- NOTE: because of this, view is not empty
{(fieldBlock && fieldBlock.fields && fieldBlock.fields.length)
? fieldBlock.fields.map((field) => (
<Text>{field.fieldValue}</Text>
))
: null
}
</View>
)
);
return (
{fieldItems && fieldItems.length)
? <View>{fieldItems}</View> : null // <-- NOTE: In this case avoid render a view without children
}
);
};
It is fine to render this:
<View />
but not this:
<View>
</View>
Cheers!

React Native Update a Flatlist Item

I want to update a specific Flatlist row when it is clicked, how can I do this? The solutions I found are all using extraData={this.state}, which is not working in my code.
const [records,setRecords] = useState([]);
//add initial data to records
...
return (
<FlatList
data={records}
keyExtractor={item => item.id}
renderItem={itemData =>
<RecordItem
onSelect={() => {
props.navigation.navigate({...})
}
}
onApply={()=>{
// in my RecordItem these is a button to call onApply(),
and I want to update the Flatlist when I click this button
var res = applyHandler();
return res;
}}
>
</RecordItem>
}
/>)
To update your flatlist item, you just have to update the data it is rendering from, in order to do this, in your onApply function you know the item index with which you can update the record index like:
const [records,setRecords] = useState([]);
//add initial data to records
...
return (
<FlatList
data={records}
keyExtractor={item => item.id}
renderItem={itemData =>
<RecordItem
onSelect={() => {
props.navigation.navigate({...})
}
}
onApply={()=>{
// here you will get reference to record item index,
const itemIndex = itemData.index;
const modRecords = [...records];
modRecords[itemIndex].title = 'NEW TITLE';
// assuming title is what you want to change
// now just update the records using setRecords
setRecords(modRecords);
}}
>
</RecordItem>
}
/>)

How to change state with useState hook using a variable

I have a FlatList with about 60 items.
Each item has a small button that is clicked to display more information inside the FlatList item.
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo() }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo ? <View><Text>{ itemData.item.info }</Text><View> : null }
The onPress toggle function is something like:
const toggleInfo = () => {
if (showInfo === true) {
setShowInfo(false);
} else {
setShowInfo(true);
}
};
Of course, since it's a FlatList, when I click the button all of the FlatList items show their hidden contents. But I only want the info for the clicked item to show, leaving all the others unchanged.
So, I changed the onPress to take an argument:
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
...which is fine. But now I need to target the right state array (which is the same as the id but with an "z" tacked on the end to avoid any variable conflicts):
const toggleInfo =(id) => { // id might be "ABC"
const infoState = `${id}z`;
const infoStateSET = `set${speciesState}`; // therefore: setABCz
// Now I want to target the state "ABCz" and "setABCz" useState variables
if (infoState === true) {
infoStateSET(false);
} else {
infoStateSET(true);
}
};
Now, obviously there is no literal "infoStateSET" to change the state but I do want to use the variable to target the set state function.
Is this possible?
You can just set the id in showInfo state and then check if showInfo id is the same as the itemData.item.id.
basically you would have a state like this.
const [showInfo, setShowInfo] = useState(null);
Then you would set the state like so using your toggleInfo function:
const toggleInfo = (id) => {
if (showInfo === id) {
setShowInfo(id);
} else {
setShowInfo(null);
}
}
Then in your Flatlist item:
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo === itemData.item.id ? <View><Text>{ itemData.item.info }</Text><View> : null }