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
);
}
Related
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.
Im working with my friends on a app project and we find an issue many times when we tring to set a use state and the console log the variable, i've looking for a solution in the website and saw that the reason is that the usestate is an async awiat which means the variable that i set in the use state isn't immidatly set in it, so i tried many solution that i found in the websites but none of them work for me.
in the screenShot you can see that the json variable is in console log before and the set varaible doesn't show after the setActiveUser , any help?
Thanks!
If you want to do something upon setting state then your best bet is to use the useEffect hook from React and adding your state in the dependency array. This will then call the function in your useEffect every time the state changes. See below a rough example:
import { Text } from 'react-native';
const MyComponent = () => {
const [activeUser, setActiveUser] = useState(null);
useEffect(() => {
// This should log every time activeUser changes
console.log({ activeUser });
}, [activeUser]);
const fetchAuthentication = async user => {
var flag = false;
await fetch('/api/authUser/', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
})
.then(res => {
res.ok && (flag = true);
return res.json();
})
.then(json => {
if (flag) {
setActiveUser(json);
}
})
.catch(error => console.error(error));
return flag;
};
return <Text>Hi</Text>;
};
Full documentation: https://reactjs.org/docs/hooks-effect.html
I got 3 pages
homepage, productList and productDetails
When going from homepage to productList I pass a route param,
navigation.navigate('productList', { showCategory: 'productListA'} )
InitialProcess when component mounted
Inside the productList page when the component is mounted. I am declaring use state like this.
const {showCateory} = route.params;
const [activeTab, setActiveTab] = useState(showCateory);
and calling api using that activeTab
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
activeTab,
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, []);
User Interaction
But I also add the button in the productList so that user can change the current active tab
<TouchableOpacity onPress={() => changeTab()}></TouchableOpacity>
const changeTab = async () => {
await setActiveTab('productListB'),
await dispatch(fetchProductList(activeTab)
}
Take note that right now active tab and data coming from api is different from when the component is start mounted.
Navigation Change again
When use goes from productList to productDetails. All thing is fine.
But inside the product details I am going back to productList with this.
navigation.goBack().
When I am back in productList page The activeTab is change back to productListA and the data is change back to when component is mounted
Can I pass or change the route params when calling navigation.goBack()?
add activeTab in useEffect depedineces.
as docs say
The array of dependencies is not passed as arguments to the effect function. Conceptually, though, that’s what they represent: every value referenced inside the effect function should also appear in the dependencies array. In the future, a sufficiently advanced compiler could create this array automatically.
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
//this value will always updated when activeTab change
activeTab,
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, [activeTab]); //<<<<< here
also you need to know setState() does not always immediately update the component. see here
so change this
const changeTab = async () => {
//await setActiveTab('productListB'),
//await dispatch(fetchProductList(activeTab)
setActiveTab('productListB')
dispatch(fetchProductList('productListB'))
}
This might be happening because route.params is still set to { showCategory: 'productListA'} when you are coming back to the screen.
If this is the case, you can fix it by Changing params object in changeTab() like
navigation.setParams({
showCategory: 'productListB',
});
I hope this will fix your problem.
This happens because the callback function inside the focus listener uses the initial value of the state when the function was defined (at initial page render) . Throughout the lifespan of listener the callback function uses this stale state value.You can read more about this behaviour in this answer
Although the answer by Ahmed Gaber works in this case as the listener is cleared and redefined after each state change.Another common work-around is to use an useRef instead of useEffect.A ref is basically a recipe that provides a mutable object that can be passed by reference.
In your case you can initialise activeTab with navigation param value using useRef hook as :
const activeTab = useRef(showCateory);
and the focus listener callback function should be changed to use the Reference current value as
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
async function fetchData() {
try {
await dispatch(
fetchProductList(
activeTab.current, //<<<<<<---------here
),
);
} catch (err) {
console.log(err);
}
}
fetchData();
});
return unsubscribe;
}, []);
and the changeTab function can directly update reference current value
const changeTab = async () => {
setActiveTab.current = 'productListB';
dispatch(fetchProductList('productListB'))
}
I am using an api call to get information for my app which I display to the user. The problem is that when I open the screen for the first time the app displays the information but when I go to a different screen and then comeback I dont see the information unless I restart the app.
This function makes the apiCall for me:
async function getOrders() {
var retrieveData = async () => {
try {
var value = await AsyncStorage.getItem("user");
var data = JSON.parse(value);
return data.user.email;
} catch (error) {
alert(error);
}
};
retrieveData().then((usr) => {
setUser(usr)
fetch(URL + "/api/order/quoted", {
method: "POST",
body: "user=" + usr,
headers: { "Content-type": "application/x-www-form-urlencoded" },
})
.then((response) => response.json())
.then((responseJson) => {
if (responseJson.error === null) {
setOrders(responseJson.orders);
}
});
});
}
First I use the retriveData function to get the used id, based on that information is server to the user.
You are using react-navigation version 5, so you need to wrap your logic fetch data in useFocusEffect hook react navigation docs
import { useFocusEffect } from '#react-navigation/native';
useFocusEffect(
React.useCallback(() => {
getOrders()
}, [getOrders])
);
The problem can be solved in the following steps:
If you want the data fetched from your endpoint to be used even if you move to other screen use Redux.
If you use redux or not and want to fetch the api every time you open a specific screen then you need to add an onfocus listener. An example is here https://reactnavigation.org/docs/navigation-events/
class Profile extends React.Component {
componentDidMount() {
this._unsubscribe = navigation.addListener('focus', () => {
// do something
});
}
Currently, I have a page which renders a list of dates, When a user presses a certain date, the user is then taken to a new page which renders the graph of the date that they pressed.
I want to use redux to update props, so that I can render a specific graph based on which button a user has pressed.
Inside my renderList() I return a mapped array that in turn returns a bunch of TouchableOpacities. Inside each TouchableOpacity, inside the onPress event, another function is called that passes all of the information about the test as a parameter. renderList looks like this.
let sorted = _.orderBy(this.props.testResults, testResult => testResult.created, 'desc');
moment.locale(localeToMomentLocale(I18n.locale));
return sorted.map((result, index) => {
let formattedDate = moment(result.created).format(I18n.t('report_header_dformat'));
let correctedDate = vsprintf(I18n.t('report_date_correction'), [formattedDate]);
let analysis = TestAnalysis.run(result);
return (
<TouchableOpacity
onPress={() => this.resultOrTest(result)}
style={styles.row} key={'_' + index}>
</TouchableOpacity>
resultOrTest looks like this:
resultOrTest = (result) => {
console.log('ReportDetailPage: resultOrTest: showing result: ', result.id);
this.props.setResultIdToProps(result.id);
this.props.navigation.navigate('ReportSinglePage');
};
mapDispatchToProps looks like this:
const mapDispatchToProps = (dispatch) => {
return {
setResultIdToProps: () => {
dispatch(setResultIdToProps());
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ReportDetailPage);
inside my actions/user.js page.
export const setResultIdToProps = (resultId) => {
// var newId = resultId.toString();
console.log('actions/user.js setResultIdToProps: resultid.......', resultId);
return (dispatch, getState) => {
dispatch({
type: SET_RESULT_ID_TO_PROPS,
resultId
});
}
};
Why does resultId keep coming back as undefined? Did I pass the wrong value/Parameter?
You need to properly pass the parameter to your action dispatcher in mapDispatchToProps. Right now, you're not passing the resultId, hence it is passed as undefined.
const mapDispatchToProps = (dispatch) => {
return {
setResultIdToProps: (resultId) => {
dispatch(setResultIdToProps(resultId));
}
}
}