Using API to fecth the next list and display for users - react-native

I am making a react-native app, I am fetching a list of movies from an API, and every time I press next I'm to supposed to get fetch the next list of movies, however, my code doesn't work correctly.
At first, you have to click on the button to fetch the first list like this:
<Button mode="contained" onPress={() => getMovieList()}>
Get Movies
</Button>
const getMovieList= async () => {
setLoading(true);
await fetchMovies(url)
.then(async (data) => {
setData(data);
// more code
})
.catch((error) => {
console.log(error);
});
};
The URL is:
const url = `https://api.themoviedb.org/4/list/${listID}?page=1&api_key=${api_key}`;
I have written a function that I can use to fetch the list using the URL above,
const [listID, setListID] = useState(1);
After I fetch the first list I show them in a child component, like this:
<MyCompanyCard
name={data.companyName}
desc={data.desc}
loadNextCompany={loadNextCompany}
loadPrevCompany={loadPrevCompany}
setListID={setListID}
listID={listID}
/>
And also:
const loadNextCompany = async () => {
setListID(listID + 1);
await getMovieCompany();
};
const loadPrevCompany = async () => {
setListID(listID - 1);
await getMovieCompany();
};
In my child component, I call the getNextOne function and the problem is, although the URL changes but the content doesn't change and I have to press next, then I can see the next list and so on, the same applies for the getPrevOne. The problem is that every time I press next/prev I make an API call but I am not sure how to set the content to change accordingly.
=================
I was able to solve it by adding a useeffet like this:
useEffect(async () => {
await getMovieCompany();
}, [listID]);
so now every time I add to listID then I fetch the url again and immdedialtly represnt the current items.

try this
const getMovieList = useCallback(() => {
const url = `https://api.themoviedb.org/4/list/${listID}?page=1&api_key=${api_key}`;
setLoading(true);
await fetchMovies(url)
.then(async (data) => {
setData(data);
// more code
})
.catch((error) => {
console.log(error);
});
}, [listID]);

I was able to solve it by adding a useeffet like this:
useEffect(async () => {
await getMovieCompany();
}, [listID]);
so now every time I add to listID then I fetch the url again and immdedialtly represnt the current items.

Related

React Native params not updating

I am trying to pass params to a detail screen for a blog post but the first time i navigate to the detail screen, the params don't get passed (shows null). then i back to original screen and click on a new blog post and it'll show params from the first blog post..
This is my function to navigate to detail screen with params:
const [blogSelected, setBlogSelected] = useState(null);
const onBlogDetail = (item) => {
setBlogSelected(item.id)
navigation.navigate( 'BlogDetail', { blog_id: blogSelected });
};
This is how i am receiving them in the detail screen:
const BlogDetailScreen = ({route}) => {
const blogID = route.params.blog_id
//Using the param in a url for an API call
const getBlogData = () => {
try{
axios.get('http://blog/'+blogID+/').then(res => {
console.log(res.data)
});
} catch (error) {
console.error(error);
}
};
}
Not sure why this is happening. Appreciate any help!! can provide more info too
try this,
const onBlogDetail = (item) => {
setBlogSelected(item.id)
navigation.navigate( 'BlogDetail', { blog_id: item.id }); // pass item.id here
};

How to get state in Nuxt js with composition api?

setup(){
const columns = computed(()=>store.state['subCategory'].subCategoryColumnsData[subCategoryName.value]);
const { fetch } = useFetch(async () => {
await store.dispatch('subCategory/getColumnsQuery', {
categories: subCategoryId.value,
page: 1,
subCategoryName: subCategoryName.value,
})
});
fetch();
}
I want to switch between pages in my project. Whenever I switched another page, I send request to get data with latest updates. This code works well for the first time when page was loaded, but it doesn't work when I switched from one page to another page. But if I check store state, I can see it in store. If I visit same page second time , I can see data this time.
But if I change my code like this, it works well. I did not get why it does not work true in the first sample
setup(){
const columns = ref([])
const { fetch } = useFetch(async () => {
await store.dispatch('subCategory/getColumnsQuery', {
categories: subCategoryId.value,
page: 1,
subCategoryName: subCategoryName.value,
})
}).then(() => (columns.value = store.state['subCategory'].subCategoryColumnsData[subCategoryName.value]));
fetch();
}
Can you test it? sample:
const state = reactive({ columns: computed(() => yourstore })
// do not need to call fetch because this hook is a function
useFetch(async () => { await store.dispatch(url) })
return {
...toRefs(state),
}

Fetch more data in RxJs

I have some problem with apply fetching "more" data using fromFetch from rxjs.
I have project with React and RXJS. Currently I'm using something like this:
const stream$ = fromFetch('https://pokeapi.co/api/v2/pokemon?limit=100', {
selector: response => response.json()
}).subscribe(data => console.log(data));
But! I would like to change limit dynamically, when I click button or even better - when I scroll to the very bottom of my website. How to make something like this?
So that, based on some interaction, the limit would change?
The way your observable work in your case it's a request-response. You're declaring stream$ to be an observable that when someone subscribes it will make a request with limit=100.
There are different ways of solving this... The most straightforward would be:
const getPokemon$ = limit =>
fromFetch('https://pokeapi.co/api/v2/pokemon?limit=' + limit, {
selector: response => response.json()
});
const MyComponent = () => {
// ...
useEffect(() => {
const sub = getPokemon$(limit).subscribe(res => console.log(res));
return () => sub.unsubscribe();
}, [limit])
// ...
}
Another option, probably a bit more reactive but harder to follow for others, would be to declare another stream which sets the limit:
const limit$ = new BehaviorSubject(100)
const pokemon$ = limit$.pipe(
switchMap(limit => fromFetch('https://pokeapi.co/api/v2/pokemon?limit=' + limit, {
selector: response => response.json()
}))
);
// In your component
const MyComponent = () => {
// ...
useEffect(() => {
const sub = pokemon$.subscribe(res => console.log(res));
return () => sub.unsubscribe();
}, [])
changeLimit = (newLimit) => limit$.next(newLimit)
// ...
}
In this other solution, you're declaring how pokemon$ should react to changes on limit$, and you can set limit$ from any other component you want.

How to remount a screen from another screen? (Refresh the whole app again with new parameters)

I have a configurable application which everything is fed into the app from a middleware (like colors and contents) based on a unique id so-called appId.
In the home screen, I am fetching all required data from a middleware in componentDidMount() function and then use it later on. For the first time, I am using a default appId and the componentDidMount() looks like this:
componentDidMount() {
this.setState({ isLoading: true });
fetch(
API +
"configurations" +
"?" +
"uuid=blabla" +
"&" +
"appId=" +
appId +
"&" +
"locale=" +
locale +
"&" +
"gid=" +
gid,
{
method: "GET",
headers: {
Accept: "application/json"
}
}
)}
I have another screen (settings screen) where I have a box and the user can insert appId as input.
When the appId is inserted by the user (in the settings page), I would like to navigate back to the Home screen and re-fetch the data with the new appId that was inserted by the user. The setting screen looks like this:
state = {
newappId: "" };
handlenewappId = text => {
this.setState({ newappId: text });
};
.....
<Item regular>
<Input
onChangeText={this.handlenewappId}
placeholder="Regular Textbox"
/>
<Button
onPress={() => {
navigation.navigate("Home");
}}
>
<Text>Save</Text>
</Button>
</Item>
However, when I do navigation.navigate("Home") the componentDidMount() is not triggered in order to fetch the data again from the middleware (which is expected since it is only triggered for the first time).
What should I do? What is the solution?
I have already tried the solution given in `componentDidMount()` function is not called after navigation
but it didn't work for me.
also tried to move the code in componentDidMount() into a separate function and call it from the settings page but I couldn't make it work.
============== UPDATE: ==============
I was able to solve the issue with the answer given by "vitosorriso" below. However, a new issue occurs. After fetching is done, I am pushing the response to the state and then use it my home screen like this:
fetchData = async () => {
this.setState({ isLoading: true }, async () => {
//fetch the data and push the response to state. e.g:
this.setState({ page: data, configs: data2, isLoading: false });
}}
....
render() {
const { configs, page, isLoading, error } = this.state; //getting the data fetched in the fetch function and pushed to the state
if (isLoading || !page || !configs) {
//if data is not ready yet
);
// Use the data to extract some information
let itemMap = page.item.reduce((acc, item) => {
acc[item.id] = item;
item.attributes = item.attributes.reduce((acc, item) => {
acc[item.key] = item.value;
return acc;
}, {});
return acc;
}, {});
}}
For the first time the app starts, everything works fine and there is no error but if I go to the settings page and press the button to navigate back to the home screen and fetch data again, I face the error:
"items.attributes.reduce is not a function".
I am assuming the reason is, "items.attributes" already has a value (from the first time) and can't fed with new data again.
Is there any way, to clear all the variables when navigating from settings page to the home page?
I have solved the same problem in my app with a similar concept of this ( `componentDidMount()` function is not called after navigation ) but using a different syntax, and it is working for me:
// your home class
// no need to import anything more
// define a separate function to fetch data
fetchData = async () => {
this.setState({ isLoading: true }, async () => {
// fetch your data here, do not forget to set isLoading to false
}
}
// add a focus listener onDidMount
async componentDidMount () {
this.focusListener = this.props.navigation.addListener('didFocus', async () => {
try {
await this.fetchData() // function defined above
} catch (error) {
// handle errors here
}
})
}
// and don't forget to remove the listener
componentWillUnmount () {
this.focusListener.remove()
}

React Native Pass data to another screen

I need to pass some data from one screen to another, but I don't know how to do it. I've searched and I read about Redux, but it is a bit complicated since I never used it and most of the tutorials are confusing for a newcomer. But if I could do it without Redux, that would be better.
So, when I click in a button, It runs this:
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson)
})
}
and I want to pass the data I get from this, to another screen.
Im using router-flux, if that matters.
you can save the response in state of your current component like
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson);
/*for react-native-router-flux you can simply do
Actions.secondPage({data:responseJson}); and you will get data at SecondPage in props
*/
this.setState({
dataToPass :responseJson
});
})
}
then below in return like you want to pass data to a new component having named as SecondPage, you can do it in following way
render(){
return(
{this.state.dataToPass && <SecondPage data ={this.state.dataToPass}>} //you will get data as props in your second page
);
}