How to play video in reverse using react-native-video? - javascript

I want to play 15 sec video. Firstly,i want to play video in simple order, after 15 seconds i want to plat video in reverse order.
In the following code, i am fetching video from local file and play in react-native-video. I want to play video as Instagram boomerang option. I also tried seek option of react-native-video option as backward but its not working.Please help me to this.
Here is my code:-
import React, { Component } from 'react';
import Modal from 'react-native-modal';
import { Avatar, Button, Icon } from 'react-native-elements';
import ImagePicker from 'react-native-image-picker';
import Video from 'react-native-video';
export default class VideoPickAndUpload extends Component {
constructor(props) {
super(props);
this.state = {
videoUri : null,
paused : false,
repeat : false,
rate : 1,
volume : 1,
resizeMode : 'contain',
duration : 0.0,
currentTime : 0.0,
rateText : 0.0,
pausedText : 'Play',
controls : true,
playIcon : 'controller-paus'
};
}
//video Select from camera or gallery
onSelectVideo = () => {
ImagePicker.showImagePicker({title:'Select Video',
takePhotoButtonTitle : 'Make Video',
maxHeight:800,maxWidth:800,
mediaType:'video',cropping:true},
video => {
if(video.didCancel){
ToastAndroid.show('Video selecting
cancel',ToastAndroid.LONG);
} else if(video.error){
ToastAndroid.show('Video selecting error :
'+video.error,ToastAndroid.LONG);
}else {
ToastAndroid.show('Video path :
'+video.uri,ToastAndroid.LONG);
this.setState({videoUri : video.uri})
}
}
)
}
//reset Video
onResetVideo = () => {
this.setState({videoUri : null})
}
onPress = () => {
if(this.state.paused == true){
this.setState({paused:false,playIcon:'controller-
paus'})
}else {
this.setState({paused:true,playIcon:'controller-play'})
}
}
//load video
onLoad = (data) => {
this.setState({duration : data.duration})
}
//load current progress
onProgress = (data) => {
this.setState({currentTime : data.currentTime})
ToastAndroid.show("Progress :
"+data.currentTime,ToastAndroid.LONG);
if(this.state.currentTime >= 15){
for(let i=data.currentTime;i>=1;i--){
this.video.seek(data.currentTime - i )
ToastAndroid.show("decrease :
"+i,ToastAndroid.LONG);
}
}
}
//when reach on end
onEnd = () => {
this.setState({pausedText : 'Play' , playIcon:'controller-
stop'})
//this.video.seek(0)
ToastAndroid.show("End :
"+this.state.currentTime,ToastAndroid.LONG);
}
//get current time percentage on progress bar
getCurrentTimePercentage() {
if(this.state.currentTime > 0){
return parseFloat(this.state.currentTime) /
parseFloat(this.state.duration)
}
return 0;
};
render() {
const {modalVisible,modalClose} = this.props;
return (
<Modal
animationIn={"bounceInRight"}
animationOut={"bounceOutRight"}
animationInTiming={500}
animationOutTiming={500}
isVisible={modalVisible}
onBackButtonPress={modalClose}
>
<View style={styles.container}>
<TouchableWithoutFeedback
onPress={() => this.onPress()}
style={{borderWidth:2,borderColor:'grey'}}
>
<Video
ref={ref => {this.video = ref}}
source={{uri: this.state.videoUri}}
style={{height:400,width:400}}
repeat={this.state.repeat}
rate={this.state.rate}
volume={this.state.volume}
resizeMode={this.state.resizeMode}
paused={this.state.paused}
onLoad={this.onLoad}
onProgress={this.onProgress}
onEnd={this.onEnd}
controls={this.state.controls}
playWhenInactive={true}
/>
</TouchableWithoutFeedback>
<View style =
{{margin:16,flexDirection:'row'}}>
<Icon
name='controller-fast-backward'
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() =>
{this.video.seek(this.state.currentTime-10)}}
/>
<Icon
name={this.state.playIcon}
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() => this.onPress()}
/>
<Icon
name='controller-fast-forward'
type='entypo'
color='#fff'
size={36}
containerStyle={{padding:16}}
onPress={() =>
{this.video.seek(this.state.currentTime+10)}}
/>
</View>
<View style =
{{margin:16,flexDirection:'row'}}>
<Button
title="Upload Video"
buttonStyle =
{{paddingHorizontal:16,paddingVertical:4}}
containerStyle = {{marginRight:8}}
onPress={()=>this.onSelectVideo()}
/>
<Button
title="Reset Video"
buttonStyle =
{{paddingHorizontal:16,paddingVertical:4}}
containerStyle = {{marginLeft:8}}
onPress={() => this.onResetVideo()}
/>
</View>
</View>
</Modal>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#212',
},
});

Use react-naitive-video-processing library for boomerang video.

Related

React native onPress or any event is not working after sometime of app load

I am using react native thunder push where continually value fluctuation happening and i am showing data on screen using mobx state management tool. all things is working fine but when i am leave the screen for 2 minute then that events are not working screen is not freezing only events is not working.
STORE
import {observable,action,makeAutoObservable} from 'mobx';
class CommonMob {
data =[];
checkAppstate ='active';
deployeStatus = true;
queryString = '?creator_id=null&tags=&exchange=null&broker_id=null&instrument_type=null&execution=null&status=null&pnl=null&broker_id=';
userToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9hcGktYXBwLnRyYWRldHJvbi50ZWNoXC9hdXRoXC9zaWduLWluIiwiaWF0IjoxNjU0ODYzMjcyLCJleHAiOjIzNTQ3MDMyNzIsIm5iZiI6MTY1NDg2MzI3MiwianRpIjoicVF6TTJHUkdQS3kyY0NCeCIsInN1YiI6MjY3NTE5LCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.QLDx1SUEJBheQbm-UqD8AOad5Oj3x3UWHBeShmn-2PE';
constructor() {
makeAutoObservable(this)
}
setData(res) {
this.data =res;
}
setAppState(val){
this.checkAppstate = val;
}
setdeployeStatus(val){
this.deployeStatus = val;
}
}
export default new CommonMob()
Screen
import {TouchableOpacity,View, Text, Button, FlatList, AppState,ScrollView,InteractionManager} from 'react-native';
import React, {useCallback, useEffect} from 'react';
import deployedStore from '../mob/deployedStore';
import {useIsFocused, useFocusEffect} from '#react-navigation/native';
import MarketStore from '../mob/deployedStore';
import {observer} from 'mobx-react-lite';
import {initThunderPush} from '../Service/ThunderConnection';
import {
fetchStrategies,
fetchFullStrategies,
} from '../Service/DeployeConnection';
import CommonStore from '../mob/commonStore';
import commonStore from '../mob/commonStore';
import Nav from '../Nav/Nav';
import { useNavigation } from '#react-navigation/native';
// import commonStore from '../mob/commonStore';
let listening = false;
const Deplyee = React.memo(observer(({navigation}) => {
// const navigation = useNavigation();
const navFun = ()=>{
alert("function call");
navigation.navigate("Dashboard")
}
useFocusEffect(
useCallback(() => {
// Do something when the screen is focused.
deployedStore.setisDeploye(true);
deployedStore.setisMarcketWatch(true);
commonStore.setdeployeStatus(true);
return () => {
// Do something when the screen is unfocused
deployedStore.setisDeploye(false);
deployedStore.setisMarcketWatch(false);
commonStore.setdeployeStatus(false);
};
}, []),
);
// React.useEffect(() => {
// }, [deployedStore.dataaa, deployedStore.strategies]);
React.useEffect(
() => {
InteractionManager.runAfterInteractions(() => {
// let timer = setTimeout(() => , 1000)
fetchFullStrategies(CommonStore.userToken);
fetchStrategies();
// fetchFullStrategies(CommonStore.userToken);
initThunderPush();
return () => {
clearTimeout(timer)
}
});
},
[[deployedStore.dataaa, deployedStore.strategies]]
)
React.useEffect(() => {
fetchStrategies();
}, [deployedStore.strategies]);
useFocusEffect(
React.useCallback(() => {
// fetchFullStrategies(CommonStore.userToken);
}, [deployedStore.strategies]),
);
React.useEffect(
() => {
if (!listening) {
initThunderPush();
listening = true;
}
setInterval(() => {
deployedStore.setCanState(true);
}, 1000);
},
[
/*strategies*/
],
);
useEffect(() => {
const appStateListener = AppState.addEventListener(
'change',
nextAppState => {
commonStore.setAppState(nextAppState);
},
);
return () => {
appStateListener?.remove();
};
}, []);
return (
<View>
<ScrollView>
<View
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
margin: 'auto',
flexWrap: 'wrap',
}}>
<Nav />
<TouchableOpacity onPress={() => alert("test pass")} ><Text>Test alert</Text></TouchableOpacity>
<TouchableOpacity onPress={() => navFun()} >
<Text>test function </Text>
</TouchableOpacity>
</View>
<Text>Deployed Strategies</Text>
{deployedStore.strategies.map(item => (
<View key={item.identifier}>
<Text style={{color: 'red', alignSelf: 'center'}}>
NAME - {item.template.name}
</Text>
<Text style={{color: 'blue', alignSelf: 'center'}}>
TYPE - {item.deployment_type}
</Text>
<Text style={{color: 'green', alignSelf: 'center'}}>
STATUS {item.status}
</Text>
<Text style={{color: 'orange', alignSelf: 'center', fontSize: 20}}>
{/* <Text style={item.sum_of_pnl >= 0 ? {color:green} : {color:red}}> */}
{item.country === 'IN'
? `${(item.sum_of_pnl, 0)} (${(
(item.sum_of_pnl /
(item.template.capital_required * item.minimum_multiple)) *
100
).toFixed(2)} %)`
: null}
</Text>
{/* <Text style={{color:'green', alignSelf:'center'}}>{item.ltp}</Text> */}
</View>
))}
<Text>market watch section</Text>
{deployedStore.dataaa.map(item => (
<View key={item.identifier}>
<Text style={{color: 'red', alignSelf: 'center'}}>
{item.identifier}
</Text>
<Text style={{color: 'green', alignSelf: 'center'}}>{item.ltp}</Text>
</View>
))}
</ScrollView>
</View>
);
}));
export default React.memo(Deplyee);

Correctly toggling playback state using react-native-track-player for live audio streaming React Native app (shoutcast)

I can't seem to get react-native-track-player fully working in my radio streaming app (shoutcast). The TouchableOpacity I use to toggle the playback seems to only work after the second press.. Even then, the toggle doesn't seem to work reliably. I think I have the logic set up incorrectly..
I also realize that I should be updating MetaData via react-native-track-player, rather than the custom hook that I wrote.
If anyone can point out my errors, I'd appreciate it! Thanks in advance 🙂
Using:
React Native 0.60.5
react-native-track-player 1.2.4
home screen logic:
...
const [playingState, setState] = useState(true)
const [song, setSong] = useState('');
const [musician, setMusician] = useState('');
useEffect(() => {
let repeat;
async function fetchData() {
try {
const res = await fetch(" * my API url ");
const json = await res.json();
setSong(json.data[0].track.title);
setMusician(json.data[0].track.artist);
repeat = setTimeout(fetchData, 26000);
} catch (error) {
console.error(error.message)
}
}
fetchData();
return () => {
if (repeat) {
clearTimeout(repeat);
}
}
}, []);
var songTitle = JSON.stringify(song)
var musicianName = JSON.stringify(musician)
const playbackState = usePlaybackState();
async function setup() {
await TrackPlayer.setupPlayer({});
await TrackPlayer.updateOptions({
stopWithApp: true,
capabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE,
TrackPlayer.CAPABILITY_STOP
],
compactCapabilities: [
TrackPlayer.CAPABILITY_PLAY,
TrackPlayer.CAPABILITY_PAUSE
]
});
}
useEffect(() => {
setup();
}, []);
async function togglePlayback() {
const currentTrack = await TrackPlayer.getCurrentTrack();
if (currentTrack == null) {
await TrackPlayer.reset();
await TrackPlayer.add({
id: 0,
title: songTitle,
url: " my audio stream URL ",
artist: musicianName,
album: null,
date: null,
genre: null}
);
await TrackPlayer.play();
} else {
if (playbackState === TrackPlayer.STATE_PAUSED) {
setState(!playingState)
await TrackPlayer.play();
} else {
await TrackPlayer.pause();
}
}
}
...
main screen front end:
...
<TouchableOpacity
onPress={() => togglePlayback()}
style={[
styles.playButtonContainer,
screenData.isLandscape && styles.playButtonContainerLandscape
]}>
{playingState ? (
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Image
source={playButton}
style={styles.playPauseButton}
resizeMode='contain'
/>
</View>
) : (
<View style={{ alignContent: 'center', justifyContent: 'center' }}>
<Pulse color='white' numPulses={3} diameter={400} speed={20} duration={2000}
style={{ alignSelf: 'center', opacity: 50, zIndex: 0 }} />
<Image
source={pauseButton}
style={styles.playPauseButton}
resizeMode='contain'
/>
<LottieView
source={visualizer}
autoPlay
loop
style={{
zIndex: 1,
width: screenWidth,
height: 200,
position: 'absolute',
alignSelf: 'center'
}}
isPaused={false}
/>
</View>
)}
</TouchableOpacity>
{
playingState ? (
<Text
style={styles.trackTitle}>{''}</Text>
) : (
<Text
style={styles.trackTitle}>{song}</Text>
)
}
{
playingState ? (
<Text style={styles.tuneInTitle}>Tap the play button to tune in</Text>
) : (
<Text style={styles.artistName}>{musician}</Text>
)
}
...

How to play a specific video on a React native ScrollView carousel?

I have a scrollview that has as a child an array of video components. It displays on the UI a carousel of videos. I would like the user to be able to click a play button that is above the video and play that video, but the way my logic is set, all the videos play together because the condition to play the video lives in a react useState.
see the code:
const VideosView = (props) => {
const videoClips = props.route.params.data;
const [state, setState] = React.useState(0);
const [play, setPlay] = React.useState(false);
return (
<>
<SafeAreaView pointerEvents='box-none' style={styles.root}>
<Header
goBack={() => props.navigation.goBack()}
title={state === 0 ? 'RYGGRöRLIGHET' : 'STYRKA & BALANS'}
/>
<View style={styles.paragraphsContainer}>
<Text style={styles.title}>
{state === 0 ? 'Ryggrörlighet' : 'Styrka & Balans'}
</Text>
<Text style={styles.paragraph}>
'Utför övningen i ca 5 min för bästa resultat.'
</Text>
<View style={styles.circlesContainer}>
{renderImages.map((_, index) => {
return (
<TouchableOpacity key={index} onPress={() => setState(0)}>
<View
style={[
styles.circles,
{ opacity: index === state ? 1 : 0.5 }
]}
/>
</TouchableOpacity>
);
})}
</View>
</View>
</SafeAreaView>
<View style={styles.scrollViewContainer}>
<ScrollView
bounces={false}
showsHorizontalScrollIndicator={false}
scrollEventThrottle={30}
onScroll={({ nativeEvent }) => {
const slide = Math.ceil(
nativeEvent.contentOffset.x / nativeEvent.layoutMeasurement.width
);
if (slide !== state) {
setState(slide);
}
}}
horizontal>
{videoClips.map((video, index) => (
<View style={{ position: 'relative' }}>
{!play && (
<TouchableOpacity
style={{
position: 'absolute',
backgroundColor: 'rgba(255,255,255,0.5)',
alignSelf: 'center',
top: 130,
width: 160,
height: 160,
borderRadius: 500,
zIndex: 4000
}}
onPress={() => setPlay(true)}></TouchableOpacity>
)}
<Video
shouldPlay={play}
key={index}
source={{
uri: video
}}
resizeMode='cover'
style={{ width: wp('100%'), height: hp('100%') }}
/>
</View>
))}
</ScrollView>
</View>
</>
);
};
I would like the user to click a button and play one video, use the carousel to go to next video, click play and play the next video.
Please, help.
If you change the play state from Boolean to Number you will probably solve your problem. Here is how:
const [videoBeingDisplayedIndex, setVideoBeingDisplayedIndex] = React.useState(5);
const [play, setPlay] = React.useState(5); // If it is equals to the video id the video should play, else it should not
...
<Button onClick={() => setPlay(videoBeingDisplayedIndex)}>
Play Video
</Button>
<VideoCarousel>
{
myVideoList.map((video, index) => {
return (
<Video
content={video}
index={index}
play={play === index} // Check if the current play state is equals to the video unique id
/>
);
})
}
</VideoCarousel>
...
PS.: please, have in mind that this snippet is abstracting the react-native elements and focusing on the problem.

How To Refresh a Screen in React Native?

I know similar questions have been asked here already, but I just can't get it to work! Im using iframe to embed a YouTube player in one of my screens (using Stack Navigator). I created an array with some YouTube Links/IDs, which are then being randomised and imported into the player, so each time I navigate to that particular screen, a random video starts playing! Now I want to add a 'play next video' button! I tried updating the screen 'key' and use different methods of forceUpdating the screen, but nothing seems to work right! Does anyone have an Idea?
Heres my code:
note that rn there is the playpause function in the 'next vid' button
import React, { useState, useCallback, useRef } from "react";
import { Button, View, Alert, Text } from "react-native";
import YoutubePlayer from "react-native-youtube-iframe";
import {NeuView, NeuButton} from 'react-native-neu-element';
import { set } from "react-native-reanimated";
//example vids
const videos = [
'iNQAp2RtXBw',
'AJqiFpAl8Ew',
'IdoD2147Fik',
]
const randomVideo = () =>
videos[Math.floor(Math.random() * videos.length)];
export default function FunnyVideos() {
const [playing, setPlaying] = useState(true);
const [videoId, setRandomVideoId] = useState(randomVideo());
function pauseOrPlay() {
return ((
setPlaying(!playing)
), []);
}
return (
<View alignItems = 'center' >
<NeuView style = {{marginTop: '15%'}} width = {330} height = {200} color = '#f2f2f2' borderRadius = {20} >
<View overflow = 'hidden' height = {169} style = {{position: 'relative', marginTop: 0}} justifyContent = 'center' alignContent = 'center' borderRadius = {10}>
<YoutubePlayer
height={'100%'}
width={300}
videoId = {videoId}
play = {playing}
/>
</View>
</NeuView>
<View flexDirection = 'row'>
<NeuButton style = {{marginTop: 60}} width = {250} height = {100} color = '#f2f2f2' title={playing ? "pause" : "play"} onPress = {pauseOrPlay} borderRadius = {20}>
<Text>
{playing ? "pause" : "play"}
</Text>
</NeuButton>
</View>
<NeuButton style = {{marginTop: 45}} width = {250} height = {100} color = '#f2f2f2' title={playing ? "pause" : "play"} onPress = {pauseOrPlay} borderRadius = {20}>
<Text>
Next Video
</Text>
</NeuButton>
</View>
);
}
Change the onPress of Next Video to () => setRandomVideoId(randomVideo())
I usually use RefreshControl, because it's simple and it can be used in other components like FlatList, ListView etc. For Example: <ScrollView contentContainerStyle={styles.scrollView} refreshControl={<RefreshControl refreshing={refreshing} onRefresh={yourFunctionHere} /> And you can read more in official docs here https://reactnative.dev/docs/refreshcontrol
I am using class component , use this.state for refresh screen,
Here is an example:
import React, { Component } from "react";
import { Button, View, Alert, Text } from "react-native";
import YoutubePlayer from "react-native-youtube-iframe";
import { NeuView, NeuButton } from 'react-native-neu-element';
import { set } from "react-native-reanimated";
const videos = [
'iNQAp2RtXBw',
'AJqiFpAl8Ew',
'IdoD2147Fik',
]
export default class FunnyVideos extends Component {
constructor(props) {
super();
this.state = {
playing: true,
videoId: videos[Math.floor(Math.random() * videos.length)],
}
}
componentDidMount = () => {
this.setState({ videoId: videos[Math.floor(Math.random() * videos.length)] });
}
pauseOrPlay() {
}
refresh = () => {
this.componentDidMount();
}
render() {
let { videoId } = this.state;
return (
<View alignItems='center' >
<NeuView style={{ marginTop: '15%' }} width={330} height={200} color='#f2f2f2' borderRadius={20} >
<View overflow='hidden' height={169} style={{ position: 'relative', marginTop: 0 }} justifyContent='center' alignContent='center' borderRadius={10}>
<YoutubePlayer
height={'100%'}
width={300}
videoId={videoId}
play={playing}
/>
</View>
</NeuView>
<View flexDirection='row'>
<NeuButton style={{ marginTop: 60 }} width={250} height={100} color='#f2f2f2' title={playing ? "pause" : "play"} onPress={this.pauseOrPlay} borderRadius={20}>
<Text>
{playing ? "pause" : "play"}
</Text>
</NeuButton>
</View>
<NeuButton style={{ marginTop: 45 }} width={250} height={100} color='#f2f2f2' title={playing ? "pause" : "play"} onPress={this.refresh()} borderRadius={20}>
<Text>
Next Video
</Text>
</NeuButton>
</View>
);
}
}

How to deselect an option that comes from Array if another one is selected

So I have a component that will render my cards called CardListing as bellow;
return getWalletPayment.map(payment => (
<CardListing
key={payment._id}
card={payment.card}
cardNo={payment.cardNo}
onChanged={selected => {
this.setState({ selectedCard: selected });
}}
/>
));
For now it will render two cards. If I select one everything is fine but if I select the second one the first one will stay selected until I tap on it again to deselect it.
Here is the implementation code
export default class CardListing extends Component {
constructor(props) {
super(props);
this.state = {
selected: false,
scaleCheckmarkValue: new Animated.Value(0)
};
this.scaleCheckmark = this.scaleCheckmark.bind(this);
this.selectPaymentOption = this.selectPaymentOption.bind(this);
}
scaleCheckmark(value) {
Animated.timing(this.state.scaleCheckmarkValue, {
toValue: value,
duration: 400,
easing: Easing.easeOutBack
}).start();
}
selectPaymentOption() {
const { selected } = this.state;
this.setState({
selected: !this.state.selected
});
this.props.onChanged(selected);
}
render() {
const { selected, scaleCheckmarkValue } = this.state;
const { card, cardNo } = this.props;
const number = cardNo.substring(15);
let logo;
if (card == "visa") {
logo = require("../../../assets/images/visa.png");
}
if (card == "master-card") {
logo = require("../../../assets/images/mastercard.png");
}
if (card == "amex") {
logo = require("../../../assets/images/amex.png");
}
if (card == "jcb") {
logo = require("../../../assets/images/jcb.png");
}
if (card == "discover") {
logo = require("../../../assets/images/discover.png");
}
const iconScale = this.state.scaleCheckmarkValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0.01, 1.6, 1]
});
const scaleValue = selected ? 1 : 0;
this.scaleCheckmark(scaleValue);
return (
<View>
<TouchableOpacity
onPress={() => this.selectPaymentOption(this, cardNo)}
style={styles.paymentOptionItem}
>
<View>
<View
style={{
flexDirection: "row",
justifyContent: "space-between"
}}
>
<View style={{ flexDirection: "row" }}>
<Image
source={logo}
style={{
width: 40,
height: 30,
marginTop: 3
}}
/>
<View
style={{
flexDirection: "column"
}}
>
<Text style={styles.paymentOptionTitle}>
{card.toUpperCase()}
</Text>
<Text style={styles.paymentOptionTitle}>Ending {number}</Text>
</View>
</View>
<Animated.View
style={[
{ transform: [{ scale: iconScale }] },
styles.iconWrapper
]}
>
<Icon name="check" color={colors.black} size={20} />
</Animated.View>
</View>
</View>
</TouchableOpacity>
<View style={styles.divider} />
</View>
);
}
}
Any idea how to solve this?
Consider externalising the 'selected' state from the <CardListing/> component, so that the parent component tracks which credit card is currently selected (rather than each <CardListing/> tracking internal state to determine if it is selected).
First lift the selected outside of <CardListing/>, to the parent component. This will involve changes to your parent components map/render function, as shown:
/*
Add this selectedCardId state to parent wallet component and
pass via selectedId. Also pass cardId prop so CardListing can
determine if it is the selected card
*/
return getWalletPayment.map(payment => (
<CardListing
key={payment._id}
card={payment.card}
cardNo={payment.cardNo}
cardId={payment._id}
selectedId={ this.state.selectedCard }
onChanged={selectedId => {
this.setState({ selectedCard: selectedId});
}}
/>
));
Next, revise the implementation of <CardListing/> so that selected is retrieved from this.props rather than this.state, and so that the cardId of the selected card is passed back via the onChanged() callback like so:
selectPaymentOption() {
/*
Pass the id of the card to be selected to callback
*/
this.props.onChanged( this.props.cardId);
}
render() {
/*
Determine if this card should be rendered a the selected
card
*/
const selected = this.selectedId === this.cardId;
/*
Remaining render method remains unchanged
*/
}
Hope this helps!

Categories