0

In the below code, when I am trying to add row with addRow Icon (faPlus) the row is getting added and the state is updated with the number of rows.

When I am trying to delete, the state is not updated with all the rows, it is always less by 1 row.

This is the code for adding a row where three text box and one delete button is added. This code updates the state with number of rows added.

 const updateRowData = () => {
        let rows = [];
        console.log('inside update row data');
        setrowCount(prevCount => prevCount + 1)
        for (let index = 0; index < rowCount; index++) {
            rows.push(
                <DataTable.Row key={index} id={index}>
                    <DataTable.Cell>
                        <Checkbox status={'checked'} />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Key" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Key${index+1}`, itemValue)}
                                />        
                            )}
                        name={`Key${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Value" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Value${index+1}`, itemValue)}
                                />
                            )}
                        name={`Value${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Description" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Description${index+1}`, itemValue)}
                                />
                            )}
                        name={`Description${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <TouchableOpacity onPress = {() => removeItem(index)}>
                            <FontAwesomeIcon icon={faBackspace} size={20} style={[KeyPairRowStyle.iconStyle]}/>
                        </TouchableOpacity>
                    </DataTable.Cell>
                </DataTable.Row>
            )
        }
        // return rows;
        setRowsState(rows)
        console.log('row state in update row data ,',rowsState.length, rowsState);
        console.log("After", rows.length);
        console.log("This row should update", rows);
    }

This is remove row, where the selected row should be deleted based on index but the state here always starts with (rowInState - 1). Current state is not reflected while deleting.

const removeItem = (i) => {
        console.log("tableRowsWhileDelete", rowsState.length);
        let a = [...rowsState]
        console.log("a", a);
        const reducedArr = a.filter((item, itemIndex) => {
            if(itemIndex !== i)
                return item  
        })

        console.log("reducedArr", reducedArr);
        setRowsState(reducedArr)
        setrowCount(reducedArr.length + 1)
    }

Prints header of row with add button.

    return (
        <View>
            <DataTable>
                <DataTable.Header>
                    <DataTable.Title></DataTable.Title>
                    <DataTable.Title>Key</DataTable.Title>
                    <DataTable.Title>Value</DataTable.Title>
                    <DataTable.Title>Description</DataTable.Title>
                    <DataTable.Title>
                        <TouchableOpacity onPress={updateRowData}>
                            <FontAwesomeIcon icon={faPlus}/>
                        </TouchableOpacity>
                    </DataTable.Title>
                </DataTable.Header>
                <View>
                    {rowsState}
                </View>
            </DataTable>
        </View>
    )
}

Full Code

import React, { useEffect, useState } from 'react'
import { StyleSheet, Text, TextInput, View } from 'react-native'
// import { Table, Row, Rows, Cell } from 'react-native-table-component';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
import TableRow from './TableRow'
import { TouchableOpacity } from 'react-native-gesture-handler'
import KeyPairCell from './KeyPairCell'
import { DataTable } from 'react-native-paper'
import { Checkbox } from 'react-native-paper'
import { faBackspace } from '@fortawesome/free-solid-svg-icons'
import KeyPairRow from './KeyPairRow'

import { Controller } from 'react-hook-form'

function KeyPair({control, setValue, resetField}) {

    const [rowCount, setrowCount] = useState(1)

    const [rowsState, setRowsState] = useState([])
    

    const updateCount = () => {
        setrowCount(prevCount => prevCount - 1);
    }

    const removeItem = (i) => {
        console.log("tableRowsWhileDelete", rowsState.length);
        let a = [...rowsState]
        console.log("a", a);
        const reducedArr = a.filter((item, itemIndex) => {
            if(itemIndex !== i)
                return item  
        })

        console.log("reducedArr", reducedArr);
        setRowsState(reducedArr)
        setrowCount(reducedArr.length + 1)
    }

    const printRow = () => {
        console.log(rowsState);
    }


    const updateRowData = () => {
        let rows = [];
        console.log('inside update row data');
        setrowCount(prevCount => prevCount + 1)
        for (let index = 0; index < rowCount; index++) {
            rows.push(
                <DataTable.Row key={index} id={index}>
                    <DataTable.Cell>
                        <Checkbox status={'checked'} />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Key" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Key${index+1}`, itemValue)}
                                />        
                            )}
                        name={`Key${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Value" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Value${index+1}`, itemValue)}
                                />
                            )}
                        name={`Value${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Description" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Description${index+1}`, itemValue)}
                                />
                            )}
                        name={`Description${index+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <TouchableOpacity onPress = {() => removeItem(index)}>
                            <FontAwesomeIcon icon={faBackspace} size={20} style={[KeyPairRowStyle.iconStyle]}/>
                        </TouchableOpacity>
                    </DataTable.Cell>
                </DataTable.Row>
            )
        }
        // return rows;
        setRowsState(rows)
        console.log('row state in update row data ,',rowsState.length, rowsState);
        console.log("After", rows.length);
        console.log("This row should update", rows);
    }

    return (
        <View>
            <DataTable>
                <DataTable.Header>
                    <DataTable.Title></DataTable.Title>
                    <DataTable.Title>Key</DataTable.Title>
                    <DataTable.Title>Value</DataTable.Title>
                    <DataTable.Title>Description</DataTable.Title>
                    <DataTable.Title>
                        <TouchableOpacity onPress={updateRowData}>
                            <FontAwesomeIcon icon={faPlus}/>
                        </TouchableOpacity>
                    </DataTable.Title>
                </DataTable.Header>
                <View>
                    {rowsState}
                </View>
            </DataTable>
        </View>
    )
}

const KeyPairRowStyle = StyleSheet.create({
    iconStyle: {
        // paddingRight: 10,
        // paddingLeft: 10,
        color: "#dc3545",
    }
})

const KeyPairStyle = StyleSheet.create({
    KeyPairContainer: {
        
    },
    iconStyle: {
        // paddingRight: 10,
        // paddingLeft: 10,
        padding: 20,
        color: "#6c757d",
    },
    textStyle: {
        fontSize: 16,
        fontWeight: "600",
        padding: 20,
        paddingLeft: 60
    },
    KeyPairHeader: {
        // width: 1124,
        flexDirection: "row",
        flex: 1,
        justifyContent: "space-between"
    },
    cellStyle: {

    },
    textInput: {
    }
})

export default KeyPair

3
  • 1
    Storing JSX in state is anti-pattern in React, store data and render the JSX from state. Using array indices as React keys is also anti-pattern, use a property or GUID so you can uniquely identify each row of data. I suspect your deletion issue is because the React keys are array indices. Commented Apr 7, 2022 at 6:58
  • 1
    @DrewReese Hi, I got your point, but my doubt is basically that when I add the rows the data itself doesn't have anything, the addition of row will then enable user to enter the data. So, in that case how can I create the JSX as map works on an array filled with item, but initially the array length is 0. Commented Apr 7, 2022 at 9:26
  • Looks like you got it figured out by your answer, but you answer your question to me, it sounds like the array length is "state". Starting from an empty array is fine, and when user adds an entry to edit, you should add an "editable" entry to the state. Commented Apr 7, 2022 at 15:42

1 Answer 1

1

So, I solve the problem by implementing DrewReese suggestion in my own way. So, on addition, I am updating my array with an object having my row data (empty), and on the basis of this array, I am mapping the JSX now.

Here's my code in case someone needs it in future. Adios.

import React, { useEffect, useState } from 'react'
import { StyleSheet, Text, TextInput, View } from 'react-native'
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'
import { faPlus } from '@fortawesome/free-solid-svg-icons'
import { TouchableOpacity } from 'react-native-gesture-handler'
import { DataTable } from 'react-native-paper'
import { Checkbox } from 'react-native-paper'
import { faBackspace } from '@fortawesome/free-solid-svg-icons'
import { Controller } from 'react-hook-form'

function KeyPair({control, setValue, resetField}) {

    const [pairState, setPairState] = useState([]);
    const [countAdd, setCountAdd] = useState(0);
    
    const pair = {
        id: countAdd,
        key: 1,
        description: 'desc' + countAdd,
        value: 'value' + countAdd,
      };

      const addHandler = () => {
        setCountAdd((prev) => prev + 1);
        const pairArray = [];
        pairArray.push(pair);
        setPairState(pairState.concat(pairArray));
      };

      const deleteHandler = (id) => {
        let a = [...pairState];
        let ind = a.findIndex((item, i) => item.id == id);
        a.splice(ind, 1);
        setPairState(a);
      };

    return (
        <View>
            <DataTable>
                <DataTable.Header>
                    <DataTable.Title></DataTable.Title>
                    <DataTable.Title>Key</DataTable.Title>
                    <DataTable.Title>Value</DataTable.Title>
                    <DataTable.Title>Description</DataTable.Title>
                    <DataTable.Title>
                        <TouchableOpacity onPress={addHandler}>
                            <FontAwesomeIcon icon={faPlus}/>
                        </TouchableOpacity>
                    </DataTable.Title>
                </DataTable.Header>
                {pairState && pairState.map((pair, i) => {
                    return (
                        <DataTable.Row key={pair.id} id={pair.id}>
                    <DataTable.Cell>
                        <Checkbox status={'checked'} />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Key" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Key${pair.id+1}`, itemValue)}
                                />        
                            )}
                        name={`Key${pair.id+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Value" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Value${pair.id+1}`, itemValue)}
                                />
                            )}
                        name={`Value${pair.id+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <Controller
                            control={control}
                            render={({field : {value}}) => (
                                <TextInput 
                                    placeholder="Description" 
                                    style={{outline: "none"}}
                                    onChangeText={ (itemValue) => setValue(`Description${pair.id+1}`, itemValue)}
                                />
                            )}
                        name={`Description${pair.id+1}`}
                        defaultValue=""
                        />
                    </DataTable.Cell>
                    <DataTable.Cell>
                        <TouchableOpacity onPress = {() => deleteHandler(pair.id)}>
                            <FontAwesomeIcon icon={faBackspace} size={20} style={[KeyPairRowStyle.iconStyle]}/>
                        </TouchableOpacity>
                    </DataTable.Cell>
                </DataTable.Row>
                    )})}
            </DataTable>
        </View>
    )
}

const KeyPairRowStyle = StyleSheet.create({
    iconStyle: {
        // paddingRight: 10,
        // paddingLeft: 10,
        color: "#dc3545",
    }
})

const KeyPairStyle = StyleSheet.create({
    KeyPairContainer: {
        
    },
    iconStyle: {
        // paddingRight: 10,
        // paddingLeft: 10,
        padding: 20,
        color: "#6c757d",
    },
    textStyle: {
        fontSize: 16,
        fontWeight: "600",
        padding: 20,
        paddingLeft: 60
    },
    KeyPairHeader: {
        // width: 1124,
        flexDirection: "row",
        flex: 1,
        justifyContent: "space-between"
    },
    cellStyle: {

    },
    textInput: {
    }
})

export default KeyPair

Sign up to request clarification or add additional context in comments.

2 Comments

For adding try setPairState(pairState => [...pairState, pair]), and for removing use array.filter like you were previously, setPairState(pairState => pairState.filter(item => item.id !== id)).
Thanks @DrewReese, I optimized my code now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.