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.