I have following code, Right now renderProductItem is rendered with fixed products. I want list to be rendered on screen load. So when screen is loaded it should call an API and render the list based on API response.
I saw solutions using state sopmething like https://github.com/vikrantnegi/react-native-searchable-flatlist/blob/master/src/SearchableList.js but the problem is when i create constructer its not getting called on screen load. So i am not sure how to use state in my case.
I am unable to figure out how to call an API on screen load and render list once response is available.
export const ProductListScreen = ({ navigation, route }): React.ReactElement => {
const displayProducts: Product[] = products.filter(product => product.category === route.name);
const renderProductItem = (info: ListRenderItemInfo<Product>): React.ReactElement => (
<Card
style={styles.productItem}
header={() => renderItemHeader(info)}
footer={() => renderItemFooter(info)}
onPress={() => onItemPress(info.index)}>
<Text category='s1'>
{info.item.title}
</Text>
<Text
appearance='hint'
category='c1'>
{info.item.category}
</Text>
<RateBar
style={styles.rateBar}
value={4}
// onValueChange={setRating}
/>
<CategoryList
style={styles.categoryList}
data={["Adventure", "Sport", "Science", "XXX"]}
/>
<Text>
The element above represents a flex container (the blue area) with three flex items.
</Text>
</Card>
);
return (
<List
contentContainerStyle={styles.productList}
data={displayProducts.length && displayProducts || products}
renderItem={renderProductItem}
/>
);
};
You can use hooks in your ProductListScreen component. You can create a state using useState hook and with the help of useEffect you achieve the behaviour of componentDidMount.
Please refer to this link:
https://reactjs.org/docs/hooks-effect.html
Use componentDidMount() to display the content. In React, this is a "lifecycle method". In the examples cited in the documentation you see that functions can be triggered when a component is added or removed. Based on your description you would want to test out componentDidMount for your code.
In the code sample you cited, you can see that this developer uses it in his class to call the makeRemoteRequest function
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `https://randomuser.me/api/?&results=20`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: res.results,
error: res.error || null,
loading: false,
});
this.arrayholder = res.results;
})
.catch(error => {
this.setState({ error, loading: false });
});
};
Here is my componentDidMount() method :
componentDidMount() {
const subscription = accelerometer.subscribe(({ x, y, z, timestamp }) => {
x = Math.trunc(x*100);
this.setState({x})
});
}
In above method, every 100 millisecond state is changing. I used that state in my render() method as below :
render() {
const animatedImageStyle = StyleSheet.flatten([
styles.captureButton,
{
transform: [{rotateZ:this.state.x + 'deg'}]
}
])
return (
<SideMenu
menu={leftMenu}
isOpen={this.state.isOpenLeftMenu}
menuPosition={'left'}
bounceBackOnOverdraw={false}
onChange={(isOpenLeftMenu) => this.updateLeftMenuState(isOpenLeftMenu)}
>
<View>
<TouchableOpacity
activeOpacity={0.5}
onPress={(this.state.recordingMode == 'camera')?() => this.takePicture():() => this.toggleRecording()}
>
<Image
source={require('../assets/imgs/forRotate.png')}
style={animatedImageStyle}
/>
</TouchableOpacity>
</View>
</SideMenu>
)
}
Now, the problem is that when I trying to open sidemenu, it is not opening, I mean it opening but hanging too much. My whole app hanging too much.
I think that's because of below method :
updateLeftMenuState(isMenuOpen) {
this.setState({
isOpenLeftMenu:isMenuOpen
})
}
Notice that I am updating another state called isOpenLeftMenu, which may blocked during I update state x.
Can anyone tell me what't going wrong here ?
you can move the animation view in a separate component along with subscription logic. So the state update of that component won't affect the SideMenu component.
Working on pulling data from an external API (FlightStats).
Currently the data fetch is working as it finds the childs of the parent request. Now stuck rendering through an array problem.
Tried multiple options for the request and data source options
Request from API:
componentDidMount() {
fetch('https://api.flightstats.com/flex/schedules/rest/v1/json/flight/AA/100/departing/2019/3/24?appId=XXXXX&appKey=+XXXXX')
.then((response) => response.json())
.then((response) => {
this.setState({
request: response.request
})
})
.catch((error) => {
console.log(error)
});
}
Constructor:
constructor() {
super();
this.state = {
request: 'carrier'
}
}
Render:
<View style={Global.container}>
<Text>{this.state.request.carrier}</Text>
{/* //={[{ key: 'a'}, { key: 'b'}]}
//renderItem={({item }) => <Text>{item.key}</Text>} */}
</View>
Data result in Json
{"request":{"carrier":{"requestedCode":"AA","fsCode":"AA"},"codeType":{},"flightNumber":{"requested":"100","interpreted":"100"},"departing":true,"date":{"year":"2019","month":"3","day":"24","interpreted":"2019-03-24"},"url":"https://api.flightstats.com/flex/schedules/rest/v1/json/flight/AA/100/departing/2019/3/24"},"scheduledFlights":[{"carrierFsCode":"AA","flightNumber":"100","departureAirportFsCode":"JFK","arrivalAirportFsCode":"LHR","stops":0,"departureTerminal":"8","arrivalTerminal":"3","departureTime":"2019-03-24T19:40:00.000","arrivalTime":"2019-03-25T06:50:00.000","flightEquipmentIataCode":"77W","isCodeshare":false,"isWetlease":false,"serviceType":"J","serviceClasses":["R","F","J","Y"],"trafficRestrictions":[],"codeshares":[{"carrierFsCode":"AY","flightNumber":"4012","serviceType":"J","serviceClasses":["F","J","Y"],"trafficRestrictions":[],"referenceCode":1139031},{"carrierFsCode":"BA","flightNumber":"1511","serviceType":"J","serviceClasses":["R","F","J","Y"],"trafficRestrictions":[],"referenceCode":1250367},{"carrierFsCode":"GF","flightNumber":"6654","serviceType":"J","serviceClasses":["J","Y"],"trafficRestrictions":["Q"],"referenceCode":2204628},{"carrierFsCode":"IB","flightNumber":"4218","serviceType":"J","serviceClasses":["R","F","J","Y"],"trafficRestrictions":[],"referenceCode":2305895},{"carrierFsCode":"LY","flightNumber":"8051","serviceType":"J","serviceClasses":["F","J","Y"],"trafficRestrictions":["Q"],"referenceCode":2942513}],"referenceCode":"807-470028--"}],"appendix":{"airlines":[{"fs":"AA","iata":"AA","icao":"AAL","name":"American Airlines","phoneNumber":"08457-567-567","active":true},{"fs":"LY","iata":"LY","icao":"ELY","name":"El Al","phoneNumber":"+ 972-3-9771111","active":true},{"fs":"AY","iata":"AY","icao":"FIN","name":"Finnair","phoneNumber":"+ 358 600 140 140","active":true},{"fs":"IB","iata":"IB","icao":"IBE","name":"Iberia","phoneNumber":"1800 772 4642","active":true},{"fs":"BA","iata":"BA","icao":"BAW","name":"British Airways","phoneNumber":"1-800-AIRWAYS","active":true},{"fs":"GF","iata":"GF","icao":"GFA","name":"Gulf Air","phoneNumber":"973 17 335 777","active":true}],"airports":[{"fs":"JFK","iata":"JFK","icao":"KJFK","faa":"JFK","name":"John F. Kennedy International Airport","street1":"JFK Airport","city":"New York","cityCode":"NYC","stateCode":"NY","postalCode":"11430","countryCode":"US","countryName":"United States","regionName":"North America","timeZoneRegionName":"America/New_York","weatherZone":"NYZ178","localTime":"2019-03-24T00:55:59.327","utcOffsetHours":-4.0,"latitude":40.642335,"longitude":-73.78817,"elevationFeet":13,"classification":1,"active":true},{"fs":"LHR","iata":"LHR","icao":"EGLL","name":"London Heathrow Airport","city":"London","cityCode":"LON","stateCode":"EN","countryCode":"GB","countryName":"United Kingdom","regionName":"Europe","timeZoneRegionName":"Europe/London","localTime":"2019-03-24T04:55:59.327","utcOffsetHours":0.0,"latitude":51.469603,"longitude":-0.453566,"elevationFeet":80,"classification":1,"active":true}],"equipments":[{"iata":"77W","name":"Boeing 777-300ER","turboProp":false,"jet":true,"widebody":true,"regional":false}]}}
Error Message:
Invariant Violation: Objects are not valid as a React child (found: object with keys {resquestedCode, fsCode}). If you meant to render a collection of childen, use an array instead.
So this is where I am stuck. The initial fetching is working and finding the sub children. For some reason not sure why I cannot render the items or just display the results from the json.
Any help or tutorials will do.
Thanks again
carrier is an object in your JSON data and hence you cannot print it directly. If you want to print it as a string, please do this.
<Text>{JSON.stringify(this.state.request.carrier)}</Text>
If you want it to look neat, you can format it like this.
<Text>{JSON.stringify(this.state.request.carrier, 0, 4)}</Text>
I am using react-table version 6.9.2 to connect to an API and display the data. My initial implementation worked fine:
componentDidMount() {
axios
.get('http://jsonplaceholder.typicode.com/posts', {
responseType: 'json'
})
.then((response) => {
this.setState({ posts: response.data });
});
}
return (
<ReactTable
columns={columns}
data={this.state.posts}
filterable
defaultPageSize={5}
noDataText={'Loading...'}
/>
);
However I want to scale up my application and connect to a database and enable server side pagination. I followed the example provided:
https://github.com/tannerlinsley/react-table/tree/v6#server-side-data
However the data is not being displayed when I implemented the below changes to my ReactTable
<ReactTable
columns={columns}
data={this.state.posts}
pages={this.state.pages}
loading={this.state.loading}
filterable
defaultPageSize={5}
noDataText={"Loading..."}
manual // informs React Table that you'll be handling sorting and pagination server-side
onFetchData={(state, instance) => {
// show the loading overlay
this.setState({ loading: true });
// fetch your data
axios
.post("http://jsonplaceholder.typicode.com/posts", {
page: state.page,
pageSize: state.pageSize,
sorted: state.sorted,
filtered: state.filtered
})
.then(res => {
// Update react-table
this.setState({
posts: res.data,
data: res.data.posts,
pages: res.data.pages,
loading: false
});
});
}}
/>
I believe I am messing up with the onFetchData function but I am not entirely sure as to what. Is there a better way to enable this? Any help would be appreciated!
I've got a working code sandbox here: https://codesandbox.io/s/yp88v0kx2z
please make few corrections in urls,callback and axios
https://codesandbox.io/s/lrn7j5vjrl?fontsize=14
There is a button 2 layers deep in a NavigatorIOS that when triggered, should change the TabBarIOS selected TabBarIOS Item.
The components are structured as follows:
--FooterTabs
------NavigatorIOS:List -> ListItem
I am attempting to do the above by having a function inside FooterTabs that changes the state, and having TabBar.Items whose prop 'selected' becomes true when the state's 'selectedTab'=== different strings.
Like so:
_changeToAlarms(){
console.log('Hello from Footer Tabs');
this.setState({
selectedTab: 'Alarms'
});
}
render(){
return(
<Icon.TabBarItemIOS title={'Alarms'}
iconName='ios-clock'
selected={this.state.selectedTab === 'Alarms'}
onPress={()=> {
this.setState({
selectedTab: 'Alarms'
});
}}>
<ComingSoon/>
</Icon.TabBarItemIOS>
<Icon.TabBarItemIOS title={'Schedules'}
iconName='ios-moon'
selected={this.state.selectedTab === 'Schedules'}
onPress={()=> {
this.setState({
selectedTab: 'Schedules'
});
}}>
</Icon.TabBarItemIOS>
);
}
*Icon.TabBatItem acts exactly like TabBarIOS.Item.
onPress works, but to be able to change the tab in a similar fashion (by modifying the component's state) I passed _changeToAlarms() as a prop to 'SleepSchedules'.
<Icon.TabBarItemIOS ...
>
<NavigatorIOS
initialRoute={{
component: SleepSchedules ,
title: ' ',
passProps: {changeToAlarms: ()=> this._changeToAlarms()}
}}
style={{flex: 1}}
/>
</Icon.TabBarItemIOS>
And from SleepSchedules, I am navigating to the next component and passing the previous'changeToAlarms' as a prop.
_handlePress(selectedSchedule){
this.setState({selectedSchedule});
this._navScheduleItem(selectedSchedule)
}
_navScheduleItem(scheduleName){
this.props.navigator.push({
title: `${scheduleName} Sleep`,
component: ScheduleItem,
passProps: {scheduleName}, changeToAlarms: ()=> this.props.changeToAlarms
})
}
render(){
return(
...
onPress={()=> this._handlePress('Monophasic')}>
);
}
And in ScheduleItem I am attempting to call the prop 'changeToAlarm' that was passed, which should be the one from Footer Tabs.
_handleTouch(){
console.log('Hello from Schedule Item');
this.props.changeToAlarms;
}
render(){
return(
...
onPress={()=> this._handleTouch()}
);
}
The console logs 'Hello from ScheduleItem' every time I press it, but doesn't log 'Hello from FooterTabs' nor does it change the tab.
Does anyone spot an error?
I am a beginner, so thank you much for your help! :)
You need a () after this.props.changeToAlarms. this.props.changeToAlarms()
I think there might be a better approach but without seeing more code its hard to get the full picture of whats going on. On thing that did catch my eye was in your _handlePress function. You called setState and then another function.
According to ReactDocs:
There is no guarantee of synchronous operation of calls to setState
and calls may be batched for performance gains.
This might be causing an issue for you, again without more code its hard to tell. You can try using the overload method for setState that takes a function as the second arg.
setState(nextState, callback)
Performs a shallow merge of nextState into current state. This is the primary > method you use to trigger UI updates from event handlers and server request > > callbacks.
The first argument can be an object (containing zero or more keys to
update) or a function (of state and props) that returns an object
containing keys to update.
This ensures your setstate completes before your next function is executed.
_handlePress(selectedSchedule){
this.setState({selectedSchedule}, () =>
{
this._navScheduleItem(selectedSchedule);
});
}