Zittack
Zittack

Reputation: 3

How to change input value using setState

i'm building a simple todo app, and i need to change the input value ( to edit tasks ). I tried to make it like in the react native docs :

export default function UselessTextInput() {
  const [value, onChangeText] = React.useState('Useless Placeholder');

  return (
    <TextInput
      style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
      onChangeText={text => onChangeText(text)}
      value={value}
    />
  );
}

But in my code i have my input inside map function and it displays an error : "undefined is not a function ( near '...todos.tasks.map...')

Can anyone explain me why do I get this error and how to solve it ?

My code :

const App = () => {

const[todos,setTodos] = useState({
  tasks: [],
  task: '',
  key: ''
})

const addItem = () => {

  if(todos.task != '' && todos.task != null){
    setTodos({
      tasks: todos.tasks.concat(todos.task),
      task: ''
    })
    console.log(todos.tasks)
  }
  else {
    Alert.alert('OOPS!', 'You need to fill in input' , [{
      text: 'Understood'
    }])
  }
}

const removeItem = arg => {
  const list = todos.tasks;
        list.splice(arg,1)
        setTodos({tasks: list})
}


const handleInputTextChange = (newText) => {
  setTodos({
    tasks: newText
  })
}

  return (

   <ScrollView keyboardShouldPersistTaps='handled'>
    <View style={styles.container}>

    <View style = {styles.header}>
      <Text style = {styles.title}>Todos</Text>
    </View>

        <View style={styles.content}>
           <TextInput
           style = {styles.input}
           placeholder = "Type new item"
           value = {todos.task}
           onChangeText = {e => setTodos({...todos, task: e, key: Date.now()})}
           />
           <ButtonSubmit text = 'Submit' onPress = {addItem}/>

           {
             todos.tasks.map((item, index) => {
               return(

            <TouchableOpacity>
              <View style = {styles.Wrapper} key = {todos.key}>
                <View style = {styles.taskWrapper}>
                  <TextInput style = {styles.task} id = {todos.key} value = {item} onChangeText={handleInputTextChange} />
                </View>
                <ButtonRemove  onPress = {() => removeItem(index)} />
              </View>
            </TouchableOpacity>
               )
             })
           }
        </View>
    </View>
  </ScrollView>
  );
}

Upvotes: 0

Views: 63

Answers (1)

Dmitriy Green
Dmitriy Green

Reputation: 81

You are overwriting your tasks array with the input value and then you get an error when trying to map tasks that is a string and not an array anymore.

Try this:


const App = () => {

  const[todos,setTodos] = useState({
    tasks: [],
    task: '',
    key: ''
  })

  const addItem = () => {

    if(todos.task != '' && todos.task != null){
      setTodos({
        tasks: todos.tasks.concat(todos.task),
        task: ''
      })
      console.log(todos.tasks)
    }
    else {
      Alert.alert('OOPS!', 'You need to fill in input' , [{
        text: 'Understood'
      }])
    }
  }

  const removeItem = arg => {
    const list = todos.tasks;
          list.splice(arg,1)
          setTodos({tasks: list})
  }


  const handleInputTextChange = (newText, index) => {
    setTodos((s) => {
      ...s,
      tasks: s.tasks.map((t, i) => i === index ? newText : t)
    })
  }

  return (

   <ScrollView keyboardShouldPersistTaps='handled'>
    <View style={styles.container}>

    <View style = {styles.header}>
      <Text style = {styles.title}>Todos</Text>
    </View>

        <View style={styles.content}>
           <TextInput
           style = {styles.input}
           placeholder = "Type new item"
           value = {todos.task}
           onChangeText = {e => setTodos({...todos, task: e, key: Date.now()})}
           />
           <ButtonSubmit text = 'Submit' onPress = {addItem}/>

           {
             todos.tasks.map((item, index) => {
               return(
                <TouchableOpacity>
                  <View style = {styles.Wrapper} key = {todos.key}>
                    <View style = {styles.taskWrapper}>
                      <TextInput style = {styles.task} id = {todos.key} value = {item} onChangeText={value => handleInputTextChange(value, index)} />
                    </View>
                    <ButtonRemove  onPress = {() => removeItem(index)} />
                  </View>
                </TouchableOpacity>
               )
             })
           }
        </View>
    </View>
  </ScrollView>
  );
}

Also, check your code for using key prop as it appears to be problematic. You should never use Date.now() as a key. Check React docs: https://reactjs.org/docs/lists-and-keys.html

Upvotes: 2

Related Questions