Delete Button for Every Input Added - javascript

I'm building this beginner react-native application that lists down its ongoing tasks and also allows users to delete the tasks when needed. I was already able to show each task but I can't figure out how to add a delete button for every task added.
Below is the code that I have come up with but I haven't been able to make a delete button for each task yet.
export default function App() {
const [newTask,setNewTask] = useState();
const [taskList,setTaskList] = useState([]);
const convertedTaskList = taskList.map((toDoTask,index)=>({
id: index+1,
activity:toDoTask,
status:'complete'
}))
function addTodoHandler(){
setTaskList([...taskList,newTask])
}
return (
<View style={styleSheet.container}>
<View style={styleSheet.contentContainer}>
<View>
<Text style={styleSheet.sectionTitle}>TO-DO LIST</Text>
</View>
<View style={styleSheet.taskContainer}>
{taskList.map((task)=><Text key={task}>{task}</Text>)}
</View>
</View>
<View style={styleSheet.addTaskWrapper}>
<TextInput placeholder="Enter Task" onChangeText={(enteredText)=>setNewTask(enteredText)}/>
<Button title="Add Task" onPress={addTodoHandler}/>
</View>
</View>
);
}
Is there a way for me to make an output just like the picture I attached through the link below?
Task w/ Delete Buttons

Try to add it in the map:
<View style={styleSheet.taskContainer}>
{taskList.map((task, index)=> (
<>
<Text key={task}>{task}</Text>
<Button title="Delete" onPress={() => setTaskList((prev) => prev.slice(index, 1))} />
</>
))}
</View>

Related

How to pass up nested state and avoid useCallback in react native

I have a parent and nest child component hierarchy of QuestionsAndAnswersScreen -> QuestionInput -> QuestionSelector -> AnswerSelector. I need to pass the question and answer object back up to the QuestionAndAnswerScreen in order to show it on the view. However I cannot find a way without going into deep nested callbacks.
Here is my code for the QuestionAnswerScreen and AnswerSelector:
function QuestionsAndAnswers() {
const {shell, body} = styles;
return (
<View style={shell}>
<SignUpHeader title="Add your answers" page={5}/>
<View style={body}>
{qAndA[1] ? <Answer question={qAndA[1].question} answer={qAndA[1].answer}/> : <QuestionInput />}
{qAndA[2] ? <Answer question={qAndA[2].question} answer={qAndA[2].answer}/> : <QuestionInput />}
{qAndA[3] ? <Answer question={qAndA[3].question} answer={qAndA[3].answer}/> : <QuestionInput />}
</View>
<SignUpFooter
title={`Questions\n& Answers`}
buttonTitle={"Done"}
disabled={false}
route="QuestionsAndAnswers"
/>
</View>
);
}
function AnswerInput(props: AnswerInputProps) {
const {question, visible, answerModalVisible} = props;
const {pickAnAnswer, doneButton, answerTextInput, questionStyle, shell, buttonText} = styles;
const [modalVisible, setModalVisible] = useState(visible)
const [answer, setAnswer] = useState('');
const navigation = useNavigation();
useEffect(() => {
setModalVisible(visible)
}, [visible])
function answerQuestion() {
setModalVisible(false);
navigation.navigate('QuestionsAndAnswers');
}
return (
<View>
<Modal style={shell}
isVisible={modalVisible}
onBackdropPress={() => {
setModalVisible(false);
answerModalVisible(false);
}}
>
<View>
<Text style={pickAnAnswer}>Add answer</Text>
</View>
<View>
<Text style={questionStyle}>{question}</Text>
</View>
<View>
<TextInput
style={answerTextInput}
placeholder="Add your answer here..."
placeholderTextColor="#878787"
onChangeText={(text: string) => setAnswer(text)}
/>
<View style={{alignItems: 'flex-end', marginTop: 44}}>
<TouchableOpacity style={doneButton} onPress={() => answerQuestion()}>
<Text style={buttonText}>
Done
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
);
}
As you can see I get my Question and Answer in the AnswerInput but then need to navigate back to the main screen in order to display them. Any help would be great thanks :)

How to reference button in card component in React Native?

I'm a newbie to React/React Native, so please go easy on me. I've been stuck on this for a little while now so could use some help. Using functional React Native by the way.
How do I reference buttons that are in a card component from another screen? Using props in the card to display the toilet object's variables isn't a problem, but the buttons that are rendered through the card I can't work out how to reference them from the component with the map. Using navigation within the card doesn't work.
Screen that I want to reference the button in
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
onPress={() => {navigation.navigate("ReviewViewAndCreate", item)}}
/* I want to reference the review button using this onPress, but right now it isn't
referencing either button /*
/>
)
})}
Card component that contains the buttons
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}
Would appreciate any help.
Thanks!
Do these changes:
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
item={item}
navigation={navigation}
/* pass item as prop to this component /*
/>
)
})}
ToiletCard component:
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {props.navigation.navigate("ReviewViewAndCreate", props.item)}}
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}

Custom pagination with ScrollView in React Native

In my app i'm using ScrollView for showing images. Below my ScrollViewcomponent i have two buttons like prev and next. I want to add custom pagination with the buttons. Also my images are coming from an array in a loop. I want 4 images to show at a time. So, the next button should show next 4 images if there are any and prev button should take 4 previous images if there are any. My ScrollView is currently like this:
<View>
<View style={{width:width,paddingHorizontal:10,paddingVertical:20}}>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false} >
{list.map((item, i)=>(
<Image key={i} source={{uri: item}}
style={{width: 80, height: 80,marginLeft:5}} />
)
)}
</ScrollView>
</View>
</View>
Below this i have two buttons.I have created two different fuctions for those. Here's what it's like now:
<View>
<Button
title="Prev"
color="#841584"
onPress={handleClickBackward}
/>
</View>
<View>
<Button
title="Next"
color="#841584"
onPress={handleClickForward}
/>
</View>
How can i manipulate with my list array so that the custom pagination works. I have tried array slice method on next but it removes the first images and i don't find those after pressing prev button.
you can use onNextPress function and add ref in scrolview
const scrollRef = useRef<ScrollView>();
const onNextPress = () => {
scrollRef.current?.scrollTo({
y : 0,//you must increase x or y
animated : true
});
}
return (
<View style={{width:width,paddingHorizontal:10,paddingVertical:20}}>
<ScrollView
ref={scrollRef}//ref
horizontal={true}
showsHorizontalScrollIndicator={false} >
{list.map((item, i)=>(
<Image key={i} source={{uri: item}}
style={{width: 80, height: 80,marginLeft:5}} />
)
)}
</ScrollView>
</View>
);

Render via map instead of for loop

I am currently using this function to render some elements & display results after a graphql query:
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
for (var i = 0; i < numberOfUsers; i++) {
const userName = data.users.nodes[i].firstName
.concat(' ')
.concat(data.users.nodes[i].lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(data.users.nodes[i].id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
}
},
[createUserRelationMutation, userData, numberOfUsers],
);
I have read that using a for loop isn't a good idea. Hence, I am trying to switch to a map but I am unable to. I couldn't figure out how to use variables like const userNamewhile using a map.
Currently, I can only test with numberOfUsers = 1so it works fine but in reality, I want all of the item contained in the Viewwhich is styled as friends. For now, there will be a separate <View style={styles.friends}>for each item. However, I want to map all items inside one single <View style={styles.friends}>
Map takes a function as its argument, which means that you can use that same code from the for loop inside of the function passed to the map, like this:
data.users.map((user) => {
const userName = user.firstName
.concat(' ')
.concat(user.lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(user.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
Just replace all instances of data.users.nodes[i] with user since that's what each object in the array is passed into the function as.
For more info about this, check this part of the React docs.
If you want everything to be contained inside the view styled as friends this is how the code should be.
You should have the map inside the view as JS code and access properties from the item variable.
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
return (
<View style={styles.friends}>
{
data.users.nodes.map(item => {
const userName = item.firstName
.concat(' ')
.concat(item.lastName);
return (<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(item.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>);
})
}
</View>
);
}
},
[createUserRelationMutation, userData, numberOfUsers],
);

Use same onPress handle with multiple TouchableOpacity

I am using a GridView to show multiple products and on click i want to go to details screen , however I am unable to find a way to identify which product grid view cell was selected / tapped by user , I think sending some parameter to handle method should do the trick.
return (
<GridView
itemDimension={130}
items={this.state.dataSource}
style={styles.gridView}
renderItem={item => (
<View style={styles.itemContainer}>
<TouchableOpacity onPress={ this.onPressStone } style={styles.itemContainer}>
<Image source = {{uri:item.url}} style={styles.imageView} />
<Text style={styles.itemName}>{item.name}</Text>
</TouchableOpacity>
</View>
)}
/>
);
You can send parameters to your function like you said.
Example
onPress={ () => this.onPressStone(item.id) }
You can pass to the method onPressStone the item and depending the item you could do that print what you want. And if you want to know who was pressed you just have to make a log with the name of the item or take the index for example
return (
<GridView
itemDimension={130}
items={this.state.dataSource}
style={styles.gridView}
renderItem={(item, index) => {
//to know who was pressed:
console.log('pressedItemName-->', item.name);
//to know index pressed:
console.log('pressedItemName-->', item);
return (
<View style={styles.itemContainer}>
<TouchableOpacity onPress={ ()=> {this.onPressStone(item)} } style={styles.itemContainer}>
<Image source = {{uri:item.url}} style={styles.imageView} />
<Text style={styles.itemName}>{item.name}</Text>
</TouchableOpacity>
</View>
)}
/>
);

Categories

Resources