React Native - How can i display data from an API? - reactjs

I'm a beginner in React Native and I am developing a movie app using The Movie Database API.
I managed to extract the info from each movie. However, I find it difficult to extract information on the casting of films. I only managed to extract data of type "String" using the function "map". I would like to know how we can extract photos from actors and improve the display of data.
Here is an example of the API data:
_displayFilm() {
const { acteur } = this.state
if (acteur != undefined) {
return (
<ScrollView style={styles.scrollview_container}>
<Text style={styles.default_text}>Acteurs(s) :{"\n"}{acteur.cast.map(function(casts){
return ( casts.name + ' ' + casts.character)
}).join("\n")}
</Text>
</ScrollView>
)
}
}
render() {
return (
<View style={styles.main_container}>
{this._displayLoading()}
{this._displayFilm()}
</View>
)
}
}
Thank you for your help

You would probably want to display this data using a FlatList rather than in a ScrollView.
FlatLists are very easy to set up and manage. You can see more about them in the docs here.
Below is some sample code to get you started. You can update your component to incorporate the following. You would need to add two functions to the body of your component; one is a key extractor and the other is a render item (I've named them appropriately). Then in your component's render method add the code for the FlatList.
Make sure you also import FlatList from react-native
...
_keyExtractor (item, index) {
return index.toString();
}
_renderItem ({ actor, index }) {
return (<Text>{actor.name} - {actor.character}</Text>);
}
render() {
return(
...
<FlatList style={{ flex: 1 }}
data={this.state.acteur.cast}
keyExtractor={this._keyExtractor.bind(this)}
renderItem={this._renderItem.bind(this)}
/>
...
);
}
...
Adding Images
To add images to your list of characters you could update the _renderItem
method to return a better styled item, that could include images etc. For networked images look to the docs again, all the information is there.
Example:
_renderItem({actor, index}) {
return (
<View style={{flexDirection: 'row'}}>
<Image
source={`https://webaddress.com${actor.profile_path}`}
style={{width:40, height:40}}
/>
<Text>{actor.name} - {actor.character}</Text>
</View>
);
}
Remember to import Image from react-native and to use the correct base url for the web address so that you can get the image.
The above should get your started and you should only have to make some minor changes to the code so that it works for you.

Related

Is there a way to use dynamic variables in React or React Native

GUEST_1 is a variable. I need to be able to change the number on the end dynamically and it would represent my variable. Is there any way to do this: currently I get GUEST_gestNumber not defined. There is different text that I get from this example GUEST_1 GUEST_2 GUEST_3
const guest = (guestNumber) => {
return (
<View>
<Text>{GUEST_guestNumber}</Text>
</View>
);
};
is this what you want?
const guest = (guestNumber) => {
return (
<View>
<Text>{'GUEST_' + guestNumber}</Text>
</View>
);
};
if not, your question is very unclear.

How to pass parameters to another screen without navigating to it

Right now to pass parameters to another screen I'm using the following:
this.props.navigation.navigate('MyWatchList', {watchLists: response});
This automatically navigates to the other screen. I'm trying to pass parameters to another screen without navigating away from the screen I'm on but I'm having trouble figuring out how to do it. I have been trying to use setParams but I have been having no success. Any help or a point in the right direction would be appreciated.
You can consider to use the asyncStorage in order to share data between your screens.
e.g
AsyncStorage.setItem('MyWatchList',JSON.stringify({watchLists: response}));
and retrieve by using
AsyncStorage.getItem('MyWatchList').then(item => {
const list = JSON.parse(item);
...
});
You can also use EventRegister
import { EventRegister } from "react-native-event-listeners";
send value like this:
<TouchableOpacity
onPress={() => {this.setState({ visibleModal: false });
EventRegister.emit("changeModalEvent", this.state.visibleModal);
}}
>
{this.state.theme == true ? (
<Icon3 name="cancel" color={Colors.night_color_text} size={30} />
) : (
<Image
source={require("../assets/images/Auto_Layout_Horizontal.png")}
style={{ height: 24, width: 24 }}
/>
)}
</TouchableOpacity>
read the value in any screen with respect to the key like this:
useEffect(() => {
let eventListner = EventRegister.addEventListener(
"changeModalEvent",
(data) => {
// console.log({ data });
setVisibleModal(data);
}
);
return () => {
EventRegister.removeEventListener(eventListner)
};
});
what i think you trying to achieve is persistent state across screen you can do that by multiple of ways
you can use global variable you will be able to read and write to them from all of your classes/functions read more here
How to use global variables in React Native?
But the most effective way is to use redux to mange your state
Redux is an open-source JavaScript library for managing and
centralizing application state.
You can Store Your Data in Array and when you navigate to next screen , Pass that Array with navigation

React Native FlatList filter with buttons

I need little help. Im trying to filter and then re-render the data/list with some buttons. I'm using a Redux for the data to be get.
Here is the default flatlist what im showing when the screen is open.
const { data } = this.props.data; // Redux data
return (
<View>
<View>
<Text>The list..</Text>
</View>
<FlatList
data={data.filter(item => item.outcome == null)}
keyExtractor={item => item.signal_id.toString()}
renderItem={({ item }) => (
<ListTips
key={item.signal_id}
competition={item.league}
event={item.event}
sport={item.sport}
outcome={item.outcome}
date={Moment(item.start_date).startOf("hour").fromNow()}
/>
)}
/>
</View>
);
And this is showing a list with Sports events and outcome of the event. I want to create a 3-4 buttons/touchable elements so I can filter the sport(item.sport.toLowerCase() == 'handball') and the list to be refresh only with Handball sports events.
I have a data for handball events of 200 and whole data is 1200, football is 400 so i click on the next button to the handball for the football, to show the list only for football.
I tried to limit the data by calling this.props.getData() from action.js from the Redux but it load the whole data again.
Basic: i want with onPress element (touchableopacity to change the data (data={data.filter(item => item.outcome == null)}) to data={data.filter(item => item.sport == 'football')} for example and load only football events.
Thanks.

How to properly update/re-render a component that is not a child React Native?

I'm using a react-navigation. More specifically, I have a materialTabNavigator nested inside of a drawerNavigator. Each tab is in itself a stackNavigator. I have a button in homeScreen, that navigates to makePost.js. There I take in information and store it to Async storage using a simple wrapper.
In Posts.js there's a FlatList displaying each post as a component. The data for the FlatList is initially set correctly after making a request from Async Storage. The problem is that this only happens when the app is first opened. I have tried many different approaches to solve this. The only way so far I've found is to continuously setState in ComponentDidUpdate() in Posts.js. Obviously this is problematic, because it re-renders constantly. I can set a flag to stop is from rendering, but then it will not re-render again.
Ultimately, what I'd like to happen is that when I hit the user is done entering their information and is ready to make a post, they hit the button in makePost.js, and the data in the FlatList of Posts.js is update.
I've tried to pass parameters using navigation, does not work, parameters get lost somewhere, probably because of the nested navigators.
I could really used some guidance on the proper way to accomplish this.
( Navigators; not sure why this is forcing to one line )
---drawer
--tabNav
-home
homeScreen.js
makePost.js
-posts
posts.js
-messages
--drawer1
--drawer2
//Posts.js
export default class Posts extends React.Component {
state = {
rows: [
{id: 0, text: "dog"},
],
}
componentDidMount() {
this.loadState();
}
loadState = () => {
var value = store.get('posts').then((res => {
if (res === null) {
res = [{id: 0, text: "default"}]
} else {
res = res
}
this.setState({rows: res})
}))
}
componentDidUpdate() {
this.loadState();
}
renderItem = ({item}) => {
return (
<BoardTab style={styles.row} />
)}
render() {
return (
<View style={styles.view}>
<FlatList
ListFooterComponent={this.renderFooter}
style={styles.container}
data={this.state.rows}
renderItem={this.renderItem}
keyExtractor={extractKey}
>
</FlatList>
<BoardScreenFooter />
</View>
);
}
And Posts.js button looks like this:
<TouchableOpacity
onPress={ () => {
this._onPressButton
this.storeFunc(this.state.newPost)
const retval = this.state.rows
this.props.navigation.navigate('Board',
{rowsID: retval});
}
}>
<Icon
reverse
name='md-camera'
type='ionicon'
color='green'
size={12}
/>
</TouchableOpacity>
storeFunc(newObj) {
newObj.id = newObj.id + 1
store.push('posts', newObj)
store.get('posts').then((res) => {
this.setState({rows: res})
})
}
Rapidly, i would say: use Redux. It alloq you to have global state in your app, which mean you can access the state anywhere (And also set them anywhere)
When opening the app, you get the data from the AsyncStore into the Redux store. You listen to the redux state (Which will be a props in your component) and display your list. When modifying your list in the other tab, you need to do 2 things:
Store the new data in the AsyncStorage
Update the state in the redux store. Since Posts.js will be listening at the redux store (as a props), it will re-render each time your data will change
A simple way to re-render a React-Navigation screen view on navigating to it:
All credit goes to Andrei Pfeiffer, Jul 2018, in his article: "Handle Tab changes in React Navigation v2" https://itnext.io/handle-tab-changes-in-react-navigation-v2-faeadc2f2ffe
I will reiterate it here in case the above link goes dead.
Simply add a NavigationEvents component to your render function with the desired listener prop:
render() {
return (
<View style={styles.view}>
<NavigationEvents
onWillFocus={payload => {
console.log("will focus", payload);
this.loadState();
}}
/>
<FlatList
ListFooterComponent={this.renderFooter}
style={styles.container}
data={this.state.rows}
renderItem={this.renderItem}
keyExtractor={extractKey}
>
</FlatList>
<PostScreenFooter />
</View>
);
}

React Navigation - Custom Header Animation

I am using React Navigation inside React Native App and i created a Custom Header Component for my routes
like this :
const Router = StackNavigator({
Main: {
screen: Main,
navigationOptions: ({navigation}) => ({
header:<Header title="Main"/>
})
},
})
when using a custom header component the native animation not working
i would like to know how can i achieve the animation in the header the same as here https://reactnavigation.org/
TL:DR; found solution to share the animated.Value / interpolation over screens code below.
Animated Custom Header React-native + React navigation
This post was taunting me for some time - I was faced with the same issue. Hopefully this will reach you even if it's couple of months later :D
So first my issue was this, I made a component for custom header like in your example, my target was having one of the StackNavigator pages, have a scrollView which would in turn manipulate the color of the header.
Similar issue, the information exchange between header and page should help you too, here it goes.
Header.js
export class HeaderBar extends Component {
componentWillMount(){
// might be a bit, ehm but worked so if you have tips how to make the code nice feel free to share
let valueToManipulate= new Animated.Value(0);
this.props.navigation.setParams({
valueToManipulate,
customkey: valueToManipulate.interpolate({
inputRange: [0, 150],
outputRange: ['rgba(0,0,0,0)', 'rgba(0,0,0,1)'],
extrapolate: 'clamp',
})
})
}
render () {
... bit of code ...
// important bit for data binding !
if( ! (this.props.navigation.state.params && this.props.navigation.state.params.customkey) ){
return null;
}
/* unless that variable on params exists we do not ! render */
... bit more of code ...
<View style={ floating }>
<Animated.View style={{backgroundColor: this.props.navigation.state.params.customkey }}> /// <<--- typical bind
<View style={{flexDirection: 'row', justifyContent: "space-between"}}>
... and rest of render ...
So this is the header bit, now for the other "fun" part:
HomePage.js
export default class HomePage extends Component<{}> {
... stufff..... :D
render() {
/* this here, again data binding !, do not let render before we have this var in state params ! */
if( !( this.props.navigation.state.params && this.props.navigation.state.params.valueToManipulate ) )
return null;
return (
<ScrollView
style={styles.container}
onScroll={ Animated.event(
[{ nativeEvent: { contentOffset: { y: this.props.navigation.state.params.valueToManipulate } } }], // <-- tadaaa
)}
bounces={false}
scrollEventThrottle={1}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
>
... moar stuff ...
}
}
And here ! Finally ! A Demo !
Animated Custom Header React-native + React navigation
I published react-navigation-collapsible.
I hope it would be helpful.
https://github.com/benevbright/react-navigation-collapsible

Resources