Search code examples
reactjsreact-nativeonpress

I'm getting unexpected behavior from my React Native handler/onPress


This is my state section..

const [searchQuery, setSearchQuery] = useState('');
    const [editedText, setEditedText] = useState('');
    const [editMode, setEditMode] = useState(false);
    const [locked, setLocked] = useState(true);
    const initialData = serverData.map((item) => ({ ...item, edited: false }));
    const [data, setData] = useState([...serverData]);

These are my handlers, the handlers in question are the edit text focused ones..

const handleLockPress = () => {
        setLocked(!locked);
    };

    const handleDeletePress = (item) => {
        const updatedData = data.filter((dataItem) => dataItem.id !== item.id);
        setData(updatedData);
    };

    const beginEditItem = (item) => {
        if (!locked) {
            setEditMode(true);
            setEditedText(item.textContent);
            setData((updatedData) =>
                updatedData.map((item) => (item.id === item.id ? { ...item, edited: true } : item))
            );
        }
    };

    const endEditItem = (item) => {
        if (!locked) {
            setEditMode(false);
            const updatedData = data.map((dataItem) =>
                dataItem.id === item.id ? { ...dataItem, edited: false, textContent: editedText } : dataItem
            );
            setData(updatedData);
        }
    };

    const handleTextChange = (itemId, text) => {
        setData((prevData) =>
            prevData.map((item) =>
                item.id === itemId ? { ...item, textContent: text, edited: true } : item
            )
        );
    };

And here is the view/car/container that contains the feature.

<View style={styles.cardContainer} >
    {data.map((item) => (
        < Card key={item.id} style={styles.card} onPress={() => { }}>
            <BlurView intensity={3}>
                <View style={styles.cardContent}>
                    <Card.Cover
                        source={item.image}
                        style={{
                            width: item.imageWidth,
                            height: item.imageHeight,
                            margin: 16,
                        }}
                    />
                    <View style={styles.textContainer}>
                        {item.edited ? (
                            <TextInput
                                style={styles.textText}
                                value={item.textContent}
                                onChangeText={(text) => handleTextChange(item.id, text)}
                                multiline
                            />
                        ) : (
                            <Caption style={styles.textText} editable={!locked}>
                                {item.textContent}
                            </Caption>
                        )}
                        {/* <Caption style={styles.textText}>Nam quis nulla. Integer malesuada. In in enim a arcu imperdiet malesuada. Sed vel lectus. Donec odio urna, tempus molestie, porttitor ut, iaculis quis, sem. Phasellus rhoncus. ...</Caption> */}
                        <View style={styles.iconContainer}>
                            <View style={{ flex: 0 }} />
                            <View style={{ flex: 10, flexDirection: "row" }}>

                                <IconButton icon={locked ? 'lock-outline' : 'lock-open-outline'} iconColor='white' onPress={handleLockPress} />
                                {locked ? (
                                    <View />
                                ) : (
                                    <View style={styles.deleteEditContainer}>
                                        <IconButton icon="delete" iconColor="white" onPress={() => handleDeletePress(item)} />
                                        <IconButton icon={editMode ? 'plus' : 'pencil'} iconColor="white" onPress={() => (editMode ? endEditItem(item) : beginEditItem(item))} />
                                    </View>
                                )}
                            </View>
                        </View>
                    </View>
                </View>
            </BlurView>
        </Card>
    ))}
</View>

I need each card to become editable once I have unlocked the card and then pressed the edit icon, then I need to edit the text that is already there, then save it by pressing the plus icon that the edit icon turns into..

Currently the edited text just goes away when I press the plus(save) icon, and isn't saved. I've been messing with it all morning, and at one point I had it so that it would save, but the edit existed in all cards, not just the one I was editing.. and right now, selecting edit makes all cards editable.

I feel like I've tangled myself up in this problem and cannot untangle myself easily. I need a rescue.

Thank you for your time.


Solution

  • So the problem is that you don't change this state at all during editing.

    const [editedText, setEditedText] = useState('');
    

    You change this state when you begin editing, and you reset it when end editing.

    on handleTextChange inside textInput you update the date directly but then you discard it with editedText.

    To fix this you need to change:

    const handleTextChange = (itemId, text) => {
        setEditedText(text);
    };
    

    Actually, you don't need that function at all you can put setEditedText directly in TextInput.

    <TextInput
        style={styles.textText}
        value={editedText}
        onChangeText={setEditedText}
        multiline
    />
    

    You also have an error in your beginEdit:

    const beginEditItem = (item) => {
        if (!locked) {
            setEditMode(true);
            setEditedText(item.textContent);
            setData((updatedData) =>
                updatedData.map((item) => (item.id === item.id ? { ...item, edited: true } : item))
            );
        }
    };
    

    You set edited to all items from your data because you use the same variable name for item the item in map shadow the input from the function.

    You need:

    const beginEditItem = (item) => {
        if (!locked) {
            const id = item.id;
            setEditMode(true);
            setEditedText(item.textContent);
            setData((updatedData) =>
                updatedData.map((item) => (id === item.id ? { ...item, edited: true } : item))
            );
        }
    };