6

I have a FlatList with two items. I need to append this list with another elements. When the user clicks on the button, the data from the text inputs should appear in the end of the FlatList. So, I've tried to push data object to the end of the list's array, but new item replaces the last one.

import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';

export default function HomeScreen() {

  var initialElements = [
    { id : "0", text : "Object 1"},
    { id : "1", text : "Object 2"},
  ]

  const [exampleState, setExampleState] = useState(initialElements);
  const [idx, incr] = useState(2);

  const addElement = () => {
    var newArray = [...initialElements , {id : toString(idx), text: "Object " + (idx+1) }];
    initialElements.push({id : toString(idx), text: "Object " + (idx+1) });
    incr(idx + 1);
    setExampleState(newArray);
  }

  return (
    <View style={styles.container}>
        <FlatList
            keyExtractor = {item => item.id}  
            data={exampleState}
            renderItem = {item => (<Text>{item.item.text}</Text>)} />
        <Button
          title="Add element"
          onPress={addElement} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    width: '100%',
    borderWidth: 1
  },
});

3 Answers 3

11

import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';

export default function HomeScreen() {

  var initialElements = [
    { id : "0", text : "Object 1"},
    { id : "1", text : "Object 2"},
  ]

  const [exampleState, setExampleState] = useState(initialElements)

  const addElement = () => {
    var newArray = [...initialElements , {id : "2", text: "Object 3"}];
    setExampleState(newArray);
  }

  return (
    <View style={styles.container}>
        <FlatList
            keyExtractor = {item => item.id}  
            data={exampleState}
            renderItem = {item => (<Text>{item.item.text}</Text>)} />
        <Button
          title="Add element"
          onPress={addElement} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    width: '100%',
    borderWidth: 1
  },
});

You are just changing the listElements array. This will NOT trigger the re rendering of the component and hence the flat list will be unchanged.

Create a state variable in the component and store your data in that so that any modification results in re rendering.

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

3 Comments

Sorry, I am new in React Native developing. How can I create a state variable in the array?
Ok, it works. But when I add new element after the third has been already added, it replaces the last element and doesn't append into the list. So, I can't add more than 3 items into the list.
I use different ids, but only one of the items appears in the bottom of the list. I updated my answer, you can check my new code.
2

I fixed the problem of replacing elements by changing array into a state variable.

import React, { useState } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
import { FlatList } from 'react-native-gesture-handler';

export default function HomeScreen() {

  const [initialElements, changeEl]  = useState([
    { id : "0", text : "Object 1"},
    { id : "1", text : "Object 2"},
  ]);

  const [exampleState, setExampleState] = useState(initialElements);
  const [idx, incr] = useState(2);

  const addElement = () => {
    var newArray = [...initialElements , {id : idx, text: "Object " + (idx+1) }];
    incr(idx + 1);
    console.log(initialElements.length);
    setExampleState(newArray);
    changeEl(newArray);
  }

  return (
    <View style={styles.container}>
        <FlatList
            keyExtractor = {item => item.id}  
            data={exampleState}
            renderItem = {item => (<Text>{item.item.text}</Text>)} />
        <Button
          title="Add element"
          onPress={addElement} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    width: '100%',
    borderWidth: 1
  },
});

Comments

2

i fixed it by defining the array outside the export function

import React, { useState } from 'react'
import { StyleSheet, View, TextInput, TouchableOpacity, Text, FlatList } from 'react-native'

let tipArray = [
    {key: '1', tip: 20},
    {key: '2', tip: 12}
]

const screen = function tipInputScreen( {navigation} ) {
    
    const [ tip, setTip ] = useState('')
    
    const addTip = ()=>{
        if(tip == "")return

        tipArray.push({key: (tipArray.length + 1).toString(), tip})
        setTip('')
    }

    const logInput = (input)=>{
        setTip(input)
    }

    const renderTip = ({ item }) => {
        return(
        <TouchableOpacity style={styles.listItem}>
            <Text style={styles.buttonText}>{`${item.tip} $`}</Text>
        </TouchableOpacity>)
    }

    return (
        <View
        style={styles.background}>
            <TextInput
            style={styles.input}
            keyboardType={'number-pad'}
            keyboardAppearance={'dark'}
            onChangeText={logInput}
            value={tip}
            />

            <TouchableOpacity
            style={styles.redButton}
            onPress={addTip}>
                <Text style={styles.buttonText}>Add Tip</Text>
            </TouchableOpacity>
        
            <FlatList
            data={tipArray}
            renderItem={renderTip}
            style={styles.flatList}
            />
        </View>
    )
}

const styles = StyleSheet.create({
    background: {
        backgroundColor: 'grey',
        paddingTop: Platform.OS === "android" ? 25:0,
        width: '100%',
        height: '100%',
        alignItems: 'center'
    },
    input: {
        marginTop:40,
        color:'white',
        fontSize:30,
        backgroundColor: "#2e2a2a",
        height: 50,
        width: '90%',
        textDecorationColor: "white",
        borderColor: 'black',
        borderWidth: 2
    },
    flatList:{
        width: "100%"
    },
    listItem: {
        width: "90%",
        height: 50,
        backgroundColor: "#2e2e2e",
        borderRadius: 25,
        marginVertical: 4,
        marginHorizontal: "5%",
        justifyContent: "center"
    },
    listItemTitle: {
        color: "white",
        textAlign: "center",
        fontSize: 18
    },
    redButton: {
        justifyContent: "center",
        width: "90%",
        height: 50,
        backgroundColor: "red",
        borderRadius: 25,
        marginHorizontal: 20,
        marginVertical: 10
    },
    buttonText: {
        color: "white",
        textAlign: "center",
        fontSize: 18
    }
})

export default screen;

this was part of an larger app, but it should do the trick, I hope it helps

Comments

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.