Home > Software design >  Foreach loop not finding item react native
Foreach loop not finding item react native

Time:10-24

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)
  }
  • Related