-1

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? 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;
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Menna Magdy
  • 355
  • 1
  • 2
  • 14

2 Answers2

0

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;

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()}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
DᴀʀᴛʜVᴀᴅᴇʀ
  • 7,681
  • 17
  • 73
  • 127
0

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.

Menna Magdy
  • 355
  • 1
  • 2
  • 14