Home > OS >  Flatlist doesn't display the list from useContext
Flatlist doesn't display the list from useContext

Time:11-12

In react native app, I have a home screen and a second screen that the user uses to add items that should be displayed on the home screen. I am using context to save the list of items. The problem is when I add items to the second screen and go to the home screen. The displayed list is empty.

Any help to explain why this happens and how to handle it? Thanks in advance Here's the Data Context export const ExpenseContext = createContext();

App.js

const Stack = createNativeStackNavigator();
function App() {
  const [expenseList, setExpenseList] = useState([]);
  return (
    <NavigationContainer>
      <ExpenseContext.Provider value={{ expenseList, setExpenseList }}>
        <Stack.Navigator>
          <Stack.Screen
            name="Home"
            component={Home}
            options={{ title: "Dashboard" }}
          />
          <Stack.Screen
            name="AddItem"
            component={AddItem}
            options={{ title: "CashFlowCreate" }}
          />
        </Stack.Navigator>
      </ExpenseContext.Provider>
    </NavigationContainer>
  );
}
export default App;

Home.js

function Home({ route, navigation }) {
  const { expenseList } = useContext(ExpenseContext);
  return (
    <View style={styles.container}>
      <Text style={styles.text}>Budget:</Text>
      <Button title=" " onPress={() => navigation.navigate("AddItem")} />
      <View>
        <FlatList
          style={styles.listContainer}
          data={expenseList}
          renderItem={(data) => <Text>{data.item.name}</Text>}
        />
      </View>
    </View>
  );
}
export default Home;

AddItem.js

function AddItem({ navigation }) {
  const { expenseList, setExpenseList } = useContext(ExpenseContext);
  const [name, setName] = useState("");
  const [amount, setAmount] = useState("");
  const itemsList = expenseList;
  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        onChangeText={(name) => setName( name )}
        value={name}
        placeholder="Name"
        keyboardType="default"
      />
      {name === "" && (
        <Text style={{ color: "red", fontSize: 12, paddingLeft: 12 }}>
          Name is required
        </Text>
      )}
      <TextInput
        style={styles.input}
        onChangeText={(amount) => setAmount( amount )}
        value={amount}
        placeholder="Amount"
        keyboardType="numeric"
      />
      {amount === "" && (
        <Text style={{ color: "red", fontSize: 12, paddingLeft: 12 }}>
          Amount is required
        </Text>
      )}
      
      <Button
        title="Add"
        style={styles.btn}
        onPress={() => {
          if (name === "" || amount === "") {
            alert("Please Enter the required values.");
          } else {
            itemsList.push({
              name: name,
              amount: amount,
            });
            setExpenseList(itemsList);
          }
        }}
      />
      <Button
        title="View Dashboard"
        style={styles.btn}
        onPress={() => {
          navigation.navigate("Home");
        }}
      />
    </View>
  );
}

export default AddItem;

CodePudding user response:

There are several areas of issues in your code. One issue I can see is in AddItem. When you set:

const itemsList = expenseList

I think you did this for:

itemsList.push({
  name: name,
  amount: amount,
});

But you should look at the spread operator and try:

setExpenseList(...expenseList, {
  name,
  amount,
})

rewrite of AddItem.js:

function AddItem({ navigation }) {
  const { expenseList, setExpenseList } = useContext(ExpenseContext)
  const [name, setName] = useState('')
  const [amount, setAmount] = useState('')

  return (
    <View style={styles.container}>
      <TextInput style={styles.input} onChangeText={setName} value={name} placeholder='Name' keyboardType='default' />
      {name === '' ? <Text style={styles.err}>Name is required</Text> : null}
      <TextInput style={styles.input} onChangeText={setAmount} value={amount} placeholder='Amount' keyboardType='numeric' />
      {amount === '' ? <Text style={styles.err}>Amount is required</Text> : null}

      <Button
        title='Add'
        style={styles.btn}
        onPress={() => {
          name === '' || amount === ''
            ? alert('Please Enter the required values.')
            : setExpenseList(...expenseList, {
                name: name,
                amount: amount,
              })
        }}
      />
      <Button title='View Dashboard' style={styles.btn} onPress={() => navigation.navigate('Home')} />
    </View>
  )
}

export default AddItem

In your Home.js your FlatList it's missing the keyExtractor and you're trying to declare a prop of title outside of <Text>, rewrite:

function Home({ navigation }) {
  const { expenseList } = useContext(ExpenseContext);

  return (
    <View style={styles.container}>
      <Text style={styles.text}>Budget:</Text>
      <Button title=" " onPress={() => navigation.navigate("AddItem")} />
      <View>
        <FlatList
          style={styles.listContainer}
          data={expenseList}
          keyExtractor={(_,key) => key.toString()}
          renderItem={(data) => <Text>{data.item.name}</Text>}
        />
      </View>
    </View>
  );
}
export default Home;

All above untested and just what I found visually because you don't provide how the data is being brought in.


Edit:

Answering to the comment. My understanding of the docs that is incorrect because keyExtractor is for identifying the id and by your commented code unless your passed in data to FlatList has a property of key then that wont work.

Also if key is not a string it should be:

keyExtractor={(item) => item.key.toString()}

CodePudding user response:

I solve it, in AddItem component remove const itemsList = expenseList; and onPress add button it should be like that instead

 onPress={() => {
          name === "" || amount === ""
            ? alert("Please Enter the required values.")
            : setExpenseList([
                ...expenseList,
                {
                  key:
                    Date.now().toString(36)  
                    Math.random().toString(36).substr(2),
                  name: name,
                  amount: amount,
                },
              ]);
        }}

I added the key because I needed later on.

  • Related