anie
anie

Reputation: 519

Handle nested states data in react native using setState

I have application for restaurant menu, the owner of the restaurant when add item to the menu there is option where he can provide the customisation for menu item so customer can select from these before place the order, before adding it to menu, the customisation will include topups for the menu item, so i gave the restaurant owner an option to enter number and based on that number TextInputs will be showing for adding the topups, for example if the owner enter number 2, two view will be displayed, in each view there is two TextInput, one for name and one for price, so the question how to save the entered data in every TextInput using setState, whereas this state structure will be like:

const [topups, setTopups] = useState({required: [] })

from every view that have two TextInput represent {'name',price} will be stored inside required in state topups

I have done the following: this is How I am displaying the TextInputs based on the entered number:

{numberOfTopupsItems > 0 &&
   <View style={{ borderRadius: 5, borderColor: colors.black, borderWidth: 1, padding: 5 }}>
       {[...Array(Number(numberOfTopupsItems)).keys()]
             .map(el =>
               <View >
                  <Text> topup item no. {el + 1}</Text>
                  <Input
                         label="Enter name of topup"
                         mode='outlined'
                         onChangeText={text => setName(text)}
                   />
                   <Input
                         label="Enter Price of topup"
                          mode='outlined'
                          keyboardType={'decimal-pad'}
                          autoCorrect={false}
                          onChangeText={text => setPrice(text)}
                    />


                </View>
          )}
     </View>
  }

from every TextInput there i set its value in state one for name and one for price and I am modifying the main state topups using this code:

  useEffect(() => {
     
        const newRTopup = Object.assign({}, topups, { required: [name, price] })
        setTopups(newRTopup)

    }, [name, price])

if user entered number 1 and set the values for name and price everything okay, however when enter a number more than one which i will i have more than one view for name and price TextInputs then it doesn't work as it delete the previous value and add the last value to the state, i have found that i should use index to store the value first but i have no idea on how to do that.

Upvotes: 0

Views: 42

Answers (1)

Francesco Clementi
Francesco Clementi

Reputation: 2102

There are multiple ways to handle this use case.

One of them is to initialize the topups items on numberOfTopupsItems changes:

useEffect(()=>{
    let top = {required: []}
    if (numberOfTopupsItems) {
        for (let i = 0; i < numberOfTopupsItems; i++){
            top.required.push({name: null, price: null})
        }
    } 
    setTopups(top)
    
},[numberOfTopupsItems])

Then you can build your view based on the initialized value and use the index to modify the state:

{numberOfTopupsItems > 0 &&
   <View style={{ borderRadius: 5, borderColor: colors.black, borderWidth: 1, padding: 5 }}>
       {topups.required
             .map((el,i) => // i is the array index
               <View >
                  <Text> topup item no. {i + 1}</Text>
                  <Input
                         label="Enter name of topup"
                         mode='outlined'
                         onChangeText={text => {
                            let newState = {...topups};
                            topups.required[i].name = text;
                            setTopups(newState)
                         }}
                   />
                   <Input
                         label="Enter Price of topup"
                          mode='outlined'
                          keyboardType={'decimal-pad'}
                          autoCorrect={false}
                          onChangeText={text => {
                            let newState = {...topups};
                            topups.required[i].price = text;
                            setTopups(newState)
                         }}
                    />


                </View>
          )}
     </View>
  }

Upvotes: 1

Related Questions