Hi there I am trying to mark a task as done by clicking the "done" icon, so it line-through the text. i Have done a foreach loop to find the item with the same id so i can change its status in order to change the style depending on it and nothing happens. For sure i am missing something, i am pretty new to this. After clicking the icon i add console log to see status and doesnt change.
This is my TaskItem
import React from 'react'
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native'
import { MaterialIcons } from '@expo/vector-icons'
const TaskItem = (props) => {
return (
<View style={styles.container}>
<View style={styles.indexContainer}>
<Text style={styles.index}>{props.index}</Text>
</View>
<View style={styles.taskContainer}>
<Text style={(props.status) ? styles.taskDone : styles.task}>{props.task}</Text>
<TouchableOpacity onPress={() => props.deleteTask()}>
<MaterialIcons
style={styles.delete}
name="delete"
size={18}
color="#fff"
/>
</TouchableOpacity>
<TouchableOpacity onPress={() => props.markTaskDone(props.id)}>
<MaterialIcons
style={styles.done}
name="done"
size={18}
color="#fff"
/>
</TouchableOpacity>
</View>
</View>
)
}
export default TaskItem
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
marginHorizontal: 20,
},
indexContainer: {
backgroundColor: '#CEAA9A',
borderRadius: 12,
marginRight: 10,
alignItems: 'center',
justifyContent: 'center',
width: 50,
height: 50,
},
index: {
color: '#fff',
fontSize: 20,
},
taskContainer: {
backgroundColor: '#CEAA9A',
borderRadius: 12,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flex: 1,
paddingHorizontal: 10,
paddingVertical: 5,
minHeight: 50,
},
task: {
color: '#fff',
width: '90%',
fontSize: 16,
},
taskDone: {
color: '#fff',
width: '90%',
fontSize: 16,
textDecorationLine: "line-through",
},
delete: {
marginLeft: 0,
},
done: {
marginLeft: 0,
},
})
And this is my App.js
import { Keyboard, ScrollView, StyleSheet, Text, View } from 'react-native';
import TaskInputField from './components/TaskInputField';
import TaskItem from './components/TaskItem';
import AsyncStorage from '@react-native-async-storage/async-storage';
export default function App() {
const [tasks, setTasks] = useState([]);
const [ appInit, setAppInit ] = useState( true )
useEffect( () => {
if( appInit ) {
getData()
setAppInit( false )
console.log('getting data...')
}
else {
storeData()
console.log('storing data...')
}
// sortData()
}, [tasks] )
const addTask = (task) => {
if (task == null) return;
const id = new Date().getTime().toString()
task = { id: id, name: task, status: false }
setTasks([...tasks, task]);
//console.log(tasks)
//console.log(task)
//console.log(item)
Keyboard.dismiss();
}
const deleteTask = (deleteIndex) => {
setTasks(tasks.filter((value, index) => index != deleteIndex));
}
const markTaskDone = (id) => {
let items = [...tasks]
items.forEach( (task) => {
if( task.id === id ) {
task.status = true }
})
//console.log(id)
//setTasks( task)
}
const storeData = async () => {
const stringified = JSON.stringify( tasks )
try {
await AsyncStorage.setItem( "listData" , stringified )
} catch (error) {
console.log( error )
}
}
const getData = async () => {
try {
const stringified = await AsyncStorage.getItem("listData")
setTasks( (stringified !== null) ? JSON.parse(stringified) : [] )
} catch (error) {
console.log( error )
}
}
return (
<View style={styles.container}>
<Text style={styles.heading}>TODO LIST</Text>
<ScrollView style={styles.scrollView}>
{
tasks.map((task, index) => {
return (
<View key={index} style={styles.taskContainer}>
<TaskItem index={index 1} task={task.name} deleteTask={() => deleteTask(index)} markTaskDone={() => markTaskDone()}/>
</View>
);
})
}
</ScrollView>
<TaskInputField addTask={addTask}/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5f4ef',
},
heading: {
color: '#CEAA9A',
fontSize: 20,
fontWeight: '600',
marginTop: 30,
marginBottom: 10,
marginLeft: 20,
},
scrollView: {
marginBottom: 70,
},
taskContainer: {
marginTop: 20,
}
});
Thanks
CodePudding user response:
ForEach just loop array and call callback function on every item , map returns new array that was changed by callback function
const markTaskDone = (id) => {
const newItems = tasks.map( (task) => {
if( task.id === id ) {
task.status = true }
})
//console.log(id)
setTasks( newItems )
}
CodePudding user response:
Your issue is here:
const markTaskDone = (id) => {
let items = [...tasks]
items.forEach( (task) => {
if( task.id === id ) {
task.status = true }
})
//console.log(id)
//setTasks( task)
}
The forEach
does not modify the array. Try mapping like this:
const markTaskDone = (id) => {
/*
here I pass a function to setTasks as I found that with arrays
that if you use the current value of the state (tasks), that
sometimes unexpected results happen.
*/
setTasks(prev=>prev.map( (task) => {
if( task.id === id ) {
task.status = true
}
return task
})
// setting task traditionally
setTasks(tasks.map(task=> {
if( task.id === id ) {
task.status = true
}
return task
}) ))
//console.log(id)
}