I don't get any errors. I use flatlist in the home page of my code without any errors but it doesn't render in the second page. It also doesn't display console.log inside renderItem.
const NamazTakibi = () => {
const [ayet, setAyet] = useState('');
const fetchAyet = async () => {
try {
const ayet = await axios.get('https://api.acikkuran.com/surah/6/verse/1?author=14');
setAyet(ayet)
} catch {
console.log("error");
}
}
useEffect(() => {
fetchAyet();
}, []);
const renderItem = ({item}) => {
return (
<Cards item={item} />
)
}
return (
<FlatList
style={styles.container}
data={ayet}
renderItem={renderItem}
/>
)
};
export default NamazTakibi;
Related
I have this simple react native app that on button click it redirects user to a page. I'm saving data in a cache so that if user clicks the store button it stores data and after refresh it sets store data. However, I would like to implement this logic on a single button, not on 2 different buttons as it is now. Can someone explain me how could I achieve this?
export const App = () => {
const [showFirstWeb, setFirstWeb] = useState(false);
const getData = async () => {
try {
const jsonValue = await AsyncStorage.getItem("#web_Key");
return setFirstWeb(JSON.parse(jsonValue));
} catch (e) {
console.log("error", e);
}
};
useEffect(() => getData, []);
const storeData = async () => {
try {
const jsonValue = JSON.stringify(showFirstWeb);
await AsyncStorage.setItem("#web_Key", jsonValue);
} catch (e) {
console.log("error", e);
}
};
return (
<View>
<View style={styles.buttonStyle}>
<Button onPress={setFirstWeb(!showFirstWeb)}/>
<Button onPress={storeData} title="store"/>
<View>
{showFirstWeb && <MyWebComponent uri="https://www.google.com/" />}
</View>
</View>
);
};
const MyWebComponent = (uri) => {
return <WebView source={uri} />;
};```
export const App = () => {
const [showFirstWeb, setFirstWeb] = useState(false);
const getData = async () => {
try {
const jsonValue = await AsyncStorage.getItem("#web_Key");
return setFirstWeb(JSON.parse(jsonValue));
} catch (e) {
console.log("error", e);
}
};
// you forgot to call the function here
useEffect(() => getData(), []);
const storeData = async () => {
try {
// get the new value
const newShowFirstWeb = !showFirstWeb
// use the new value
setFirstWeb(newShowFirstWeb)
const jsonValue = JSON.stringify(newShowFirstWeb );
await AsyncStorage.setItem("#web_Key", jsonValue);
} catch (e) {
console.log("error", e);
}
};
return (
<View>
<View style={styles.buttonStyle}>
<Button onPress={storeData} title="store"/>
<View>
{showFirstWeb && <MyWebComponent uri="https://www.google.com/" />}
</View>
</View>
);
};
I have multiple component which has state change during its data collection from get api call, are called from a single component get re-render multiple times , Please help to avoid re-render when open this page
const MyData = () => {
const [data, setData] = useState("");
const [newData, setNewData] = useState("");
const getData = () => {
axios.get("url").then(async function (response) {
setData(response);
});
};
const getData2 = () => {
axios.get("url").then(async function (response) {
setNewData(response);
});
};
useEffect(() => {
getData();
getData2();
});
const NewData = () => {
return (
<View>
<Text>{data.name}</Text>
</View>
);
};
const RewData = () => {
return (
<View>
<Text>{newData.name}</Text>
</View>
);
};
return (
<View>
<NewData />
<RewData />
</View>
);
};
You provide no dependency array (undefined) to your useEffect. If the component's state changes, then the useEffect will be called again, which sets the state again, and so on.
You can provide an empty dependency array which will cause the useEffect to be called only once.
useEffect(() => {
getData();
getData2();
}, []);
Edit: In response to the comments. You can prevent the screens content from rendering until the data has been fetched as follows.
const MyData = () => {
const [data, setData] = useState();
const [newData, setNewData] = useState();
const getData = () => {
axios.get("url").then(async function (response) {
setData(response);
});
};
const getData2 = () => {
axios.get("url").then(async function (response) {
setNewData(response);
});
};
useEffect(() => {
getData();
getData2();
}, []);
if (!data || !newData) {
return null
}
const NewData = () => {
return (
<View>
<Text>{data.name}</Text>
</View>
);
};
const RewData = () => {
return (
<View>
<Text>{newData.name}</Text>
</View>
);
};
return (
<View>
<NewData />
<RewData />
</View>
);
};
Agenda doesn't update even when new data are added. Only when the app is reloaded it updates.
Here is my code:
const CalendarScreen = () => {
const list = useSelector((state) => state.getTodo.list);
const [items, setItems] = useState({});
const loadItems = () => {
list.forEach((data) => {
const strTime = data.createdDate;
if (!items[strTime]) {
items[strTime] = [];
list.forEach((datalist) => {
items[strTime].push({
name: datalist.title,
});
});
}
});
const newItems = {};
Object.keys(items).forEach((key) => {
newItems[key] = items[key];
});
setItems(newItems);
};
const renderItem = (item) => {
return (
<View >
<Text>{item.name}</Text>
</View>
);
};
return (
<View style={flex: 1}>
<Agenda
items={items}
loadItemsForMonth={loadItems}
renderItem={renderItem}
pastScrollRange={1}
futureScrollRange={1}
/>
</View>
);
};
export { CalendarScreen };
Expectation: Just want the Agenda to update automatically when new data is added in the state instead of having to reload the app.
It looks like that refresh depends call of loadItemsForMonth.
Unfortunately I cannot see when Agenda call loadItemsForMonth
The Text object continues to display "Pokemon" instad of pokemon.name. Any ideas?
export default function App() {
const getRandomPokemon = async () => {
const randomID = Math.floor(Math.random() * 898);
const uri = `https://pokeapi.co/api/v2/pokemon/${randomID}`;
return fetch(uri)
.then(response => response.json())
.then(data => {
return {
name: data.forms[0].name,
height: data.height,
weight: data.weight,
};
})
}
const [FirstCard, setFirstCard] = React.useState("Pokemon");
return (
<View style={styles.container}>
<CardStack
loop={true}
style={styles.cardStack}
onSwipeStart={async () => {
const pokemon = await getRandomPokemon();
setFirstCard(await pokemon.name)
console.log(pokemon)
}}
>
<Card style={styles.card}><Text>{FirstCard}</Text></Card>
<Card style={styles.card}><Text>2</Text></Card>
</CardStack>
</View>
);
}
const styles = StyleSheet.create({
...
});
Probably pokemon.name is not a Promise. You should remove the await before pokemon.name in this case.
it's a problem with the package you are using. see
github.com/lhandel/react-native-card-stack-swiper/issues/76
you don't need to await for anything, just fetch and set the first card in the then function.
export default function App() {
const [FirstCard, setFirstCard] = React.useState("Pokemon");
const getRandomPokemon = () => {
const randomID = Math.floor(Math.random() * 898);
const uri = `https://pokeapi.co/api/v2/pokemon/${randomID}`;
fetch(uri)
.then(response => response.json())
.then(data => {
setFirstCard(data.forms[0].name);
})
}
useEffect(()=>{console.log(FirstName);},[FirstCard]);
return (
<View style={styles.container}>
<CardStack
loop={true}
style={styles.cardStack}
onSwipeStart={() => {
getRandomPokemon();
}}
>
<Card style={styles.card}><Text>{FirstCard}</Text></Card>
<Card style={styles.card}><Text>2</Text></Card>
</CardStack>
</View>
);
}
I have a main screen where you can see multiple items displayed in card form you can access an item by pressing it to see its details, on the details screen I added a bookmark option that save the item using async storage, you can also check the saved items on a different screen called savedItems screen.
The problem is :
when i bookmark an item it get saved properly and i can go to the savedItems screen and find it there, but some times i have to reload the app for the item to appear on the savedItems screen why is that ?
if i book multiple items they all get saved ( on console.log ) but only the last one appears for some reason i never get more then one item displayed on the SavedItems screen
Bellow is snippets of the code used to book mark ( saved an item on its details screen )
Details.js
const DetailScreen = (props) => {
const [saved, setSaved] = useState([]);
const [items, setItems] = useState(props.route.params);
const onSave = (item) => {
const newItems = [...saved, item];
setSaved(newItems);
const items = JSON.stringify(newItems);
SaveItem("saved", items).then((res) => {
console.log("saved", res);
});
};
const goToDetails = () => {
setSaved([]);
props.navigation.navigate("SaveScreen");
};
const { width, height } = Dimensions.get("window");
const { data } = props.route.params; // this returns the data from each article
//ReadItem("saved").then((res) => console.log(res));
return (
<TouchableOpacity
...
onPress={() => {
onSave(data);
}}
>
<MaterialCommunityIcons
name="bookmark"
size={35}
color={colors.shade2}
/>
</TouchableOpacity>
)
SaveScreen.js
export default class Details extends Component {
state = {
saved: [],
};
removeItem = () => {
DeleteItem("saved")
.then((res) => {
this.setState({
saved: [],
});
console.log(res);
})
.catch((e) => console.log(e));
};
componentDidMount = () => {
ReadItem("saved")
.then((res) => {
if (res) {
const saved = JSON.parse(res);
this.setState({
saved: saved,
});
}
})
.catch((e) => console.warn(e));
};
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => index.toString()}
data={this.state.saved}
renderItem={({ item }) => {
return (
<TouchableScale
activeScale={0.9}
tension={50}
friction={7}
useNativeDriver
onPress={() =>
this.props.navigation.navigate("DetailScreen", { data: item })
}
>
<Card item={item} />
</TouchableScale>
);
}}
/>
{this.state.saved.length > 0 && (
<TouchableOpacity onPress={this.removeItem} style={styles.button}>
<Text style={styles.save}>Remove Key</Text>
</TouchableOpacity>
)}
</View>
);
}
}
the code used to save data using async storage
Dbhelper.js
import { AsyncStorage } from "react-native";
export const SaveItem = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
console.log("saved");
} catch (e) {
console.log(e);
}
};
export const ReadItem = async (key) => {
try {
var result = await AsyncStorage.getItem(key);
return result;
} catch (e) {
return e;
}
};
export function MultiRead(key, onResponse, onFailure) {
try {
AsyncStorage.multiGet(key).then((values) => {
let responseMap = new Map();
values.map((result, i, data) => {
let key = data[i][0];
let value = data[i][1];
responseMap.set(key, value);
});
onResponse(responseMap);
});
} catch (error) {
onFailure(error);
}
}
export async function DeleteItem(key) {
try {
await AsyncStorage.removeItem(key);
return true;
} catch (exception) {
return false;
}
}
if i book multiple items they all get saved ( on console.log ) but only the last one appears for some reason i never get more then one item displayed on the SavedItems screen
I think the problem is when you save new item you remove old items. You have to read old items when you mount DetailScreen. Or you can read items inside onSave method. It's more safety. It depends your application architecture
const DetailScreen = (props) => {
const [items, setItems] = useState(props.route.params);
const onSave = (item) => {
let saved = [];
ReadItem("saved")
.then((res) => {
if (res) {
saved = JSON.parse(res);
}
const newItems = [...saved, item];
const items = JSON.stringify(newItems);
SaveItem("saved", items).then((res) => {
console.log("saved", res);
});
})
.catch((e) => console.warn(e));
};
const goToDetails = () => {
setSaved([]);
props.navigation.navigate("SaveScreen");
};
const { width, height } = Dimensions.get("window");
const { data } = props.route.params; // this returns the data from each article
//ReadItem("saved").then((res) => console.log(res));
return (
<TouchableOpacity
...
onPress={() => {
onSave(data);
}}
>
<MaterialCommunityIcons
name="bookmark"
size={35}
color={colors.shade2}
/>
</TouchableOpacity>
)
when i bookmark an item it get saved properly and i can go to the savedItems screen and find it there, but some times i have to reload the app for the item to appear on the savedItems screen why is that ?
I have only one idea why it may happens. In some cases, you don't unmount SaveScreen. When you return to the SaveScreen componentDidMount is not called. Just try to add console.log to componentDidMount and when you reproduce this behavior if console.log is missed it means you SaveScreen wasn't unmounted
To handle all cases you can try to do that:
export default class Details extends Component {
state = {
saved: [],
};
removeItem = () => {
DeleteItem("saved")
.then((res) => {
this.setState({
saved: [],
});
console.log(res);
})
.catch((e) => console.log(e));
};
componentDidMount = () => {
this.readItems();
this.unsubscribe = navigation.addListener('focus', this.readItems);
};
componentWillUnmount() {
this.unsubscribe();
}
readItems = () => {
ReadItem("saved")
.then((res) => {
if (res) {
const saved = JSON.parse(res);
this.setState({
saved: saved,
});
}
})
.catch((e) => console.warn(e));
}
render() { ... }
}