How to navigate other component when use bind()? - react-native

I use react-navigation to navigate other component.
Now i want to navigate to other component with some params(selectedCity、firstSliderValue、secondSliderValue), but onAccept() function will get the error
TypeError: Cannot read property 'bind' of undefined
When i added the params before, i can navigate to my MovieClostTime component. Why i can not add params ? What should i do ?
Any help would be appreciated. Thanks in advance.
Here is my part of code:
constructor(props) {
super(props);
this.state = {
showModal: false,
selectedCity: 'Keelung',
firstSliderValue: 18,
secondSliderValue: 21
};
}
// it will close <Confirm /> and navigate to MovieCloseTime component
onAccept() {
this.setState({ showModal: !this.state.showModal });
const { selectedCity, firstSliderValue, secondSliderValue } = this.state;
console.log(selectedCity); // Keelung
console.log(firstSliderValue); // 18
console.log(secondSliderValue); // 21
this.props.navigation.navigate('MovieCloseTime', {
selectedCity,
firstSliderValue,
secondSliderValue
});
}
// close the Confirm
onDecline() {
this.setState({ showModal: false });
}
render() {
if (!this.state.isReady) {
return <Expo.AppLoading />;
}
const movies = this.state.movies;
console.log('render FirestScrren');
return (
<View style={{ flex: 1 }}>
{/* Other View */}
{/* <Confirm /> is react-native <Modal />*/}
<Confirm
visible={this.state.showModal}
onAccept={this.onAccept.bind(this)}
onDecline={this.onDecline.bind(this)}
onChangeValues={this.onChangeValues}
>
</Confirm>
</View>
);
}
My Confirm.js
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { DropDownMenu } from '#shoutem/ui';
import TestConfirm from './TestConfirm';
import { CardSection } from './CardSection';
import { Button } from './Button';
import { ConfirmButton } from './ConfirmButton';
const Confirm = ({ children, visible, onAccept, onDecline, onChangeValues }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType="slide"
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
<TestConfirm onChangeValues={onChangeValues} />
{/* <Text style={textStyle}>
{children}
</Text> */}
</CardSection>
<CardSection>
<ConfirmButton onPress={onAccept}>Yes</ConfirmButton>
<ConfirmButton onPress={onDecline}>No</ConfirmButton>
</CardSection>
</View>
</Modal>
);
};
const styles = {
// some style
};
export { Confirm };

Related

React native components not working properly

I have this custom button component :
import React, { Component } from "react";
import { View, Text, TouchableOpacity } from "react-native";
import { styles } from "./styles";
class TransactionFees extends Component {
test = () => {
const { speed, eth, usd,pressed,changeColor } = this.props;
console.log("speed, eth, usd,pressed,changeColor",speed, eth, usd,pressed,changeColor)
}
render() {
const { speed, eth, usd,pressed,changeColor,key } = this.props;
return (
<TouchableOpacity style={ pressed ? styles.pressedButton : null } onPress={changeColor}>
<Text style={styles.transactionFeeTitle}>{speed}</Text>
<Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
<Text style={styles.transactionFeeSubText}>$ {usd} </Text>
</TouchableOpacity>
);
}
}
export default TransactionFees;
This is how I use it:
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"slow"} speed={"Slow"} eth={"0.000010"} usd={"0.02"} />
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"average"} speed={"Average"} eth={"0.000030"} usd={"0.03"} />
<TransactionFees pressed={pressed} changeColor={this.changeColor} key={"fast"} speed={"Fast"} eth={"0.000050"} usd={"0.04"} />
changeColor function:
changeColor = () => {
const {pressed} = this.state
this.setState({pressed:!pressed})
}
When clicked I want only one of them to change the background style but the problem is when clicking on any of them,all of them change the background stye any solutions on how to solve this please?
You will have to maintain the pressedKey in the parent instead of maintaining the pressed something like below. Here we pass the selected key using the changeColor and maintain that in the parent which will be used to compare and decide the backgroud color.
class TransactionFeesContainer extends Component {
state = {
selectedKey: null,
};
changeColor = (key) => {
this.setState({ selectedKey: key });
};
render() {
return (
<View>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'slow'}
speed={'Slow'}
eth={'0.000010'}
usd={'0.02'}
/>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'average'}
speed={'Average'}
eth={'0.000030'}
usd={'0.03'}
/>
<TransactionFees
selectedKey={this.state.selectedKey}
changeColor={this.changeColor}
speedkey={'fast'}
speed={'Fast'}
eth={'0.000050'}
usd={'0.04'}
/>
</View>
);
}
}
class TransactionFees extends Component {
render() {
const { speed, eth, usd, speedkey, selectedKey } = this.props;
return (
<View>
<TouchableOpacity
style={speedkey === selectedKey ? styles.pressedButton : null}
onPress={() => {
this.props.changeColor(speedkey);
}}>
<Text style={styles.transactionFeeTitle}>{speed}</Text>
<Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
<Text style={styles.transactionFeeSubText}>$ {usd} </Text>
</TouchableOpacity>
</View>
);
}
}

How to separate API call using react natives context API?

I am new to react native. I have following component in my project for now I have written for fetching API in same component but want to separate it out. I am getting difficulty for how can i access variable which I am using in "getAlbum" method from outside of component.
I am trying to do this using new concept context API . is this possible using context API and how?
Is there standard way to separate API call from component?
import React, { Component } from 'react';
import {
FlatList, Text, View, Image, TouchableOpacity,
} from 'react-native';
import { ActivityIndicator, Provider } from 'react-native-paper';
import axios from 'axios';
import styles from '../style/ThumbnailView.component.style';
import ErrorAlert from '../common/ErrorAlert';
import * as myConstant from '../common/Constants';
export default class HomeScreen extends Component {
// For to Navigation header
static navigationOptions = () => ({
headerTitle: 'Album Information',
});
constructor(props) {
super(props);
this.state = {
isLoading: true,
apiLoadingError: false,
};
}
getAlbums() {
const { navigation } = this.props;
const albumId = navigation.getParam('albumID', 'no data');
axios
.get(
myConstant.API + `photos?albumId=${albumId}`, {timeout: myConstant.TIMEOUT}
)
.then((response) => {
this.setState({
isLoading: false,
dataSource: response.data,
});
})
.catch(err => {
this.setState({isLoading: false, apiLoadingError: true})
});
}
componentDidMount() {
this.getAlbums();
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 30 }}>
<ActivityIndicator animating={true} size='large' />
</View>
);
}
if (this.state.apiLoadingError) {
return (
<ErrorAlert />
);
}
return (
<React.Fragment>
<Provider>
<View style={styles.listContainer} >
<FlatList
testID='flatlist'
data={ this.state.dataSource } numColumns={3}
renderItem={({ item }) => <View style={styles.listRowContainer}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('AlbumDetailsViewScreen', {
albumTitle: item.title, albumImg: item.url
})} style={styles.listRow}>
<View style={styles.listTextNavVIew}>
<Image source = {{ uri: item.thumbnailUrl }} style={styles.imageViewContainer} />
</View>
</TouchableOpacity>
</View>
}
keyExtractor = { (item, index) => index.toString() }
/>
</View>
</Provider>
</React.Fragment>
);
}
}

Why isn't the Todo class rendering

I have the following script. It's not quite there yet but I'm stuck on getting the class to render
Here's where I think I'm messing up:
{this.state.todos.map(todo=>{
<Todo
onToggle={()=>(this.toggle(todo.id))}
onDelete={()=>(this.removeTodo(todo.id))}
todo={todo}
key={todo.id}
/>})}
and here's the entire code:
import React from 'react';
import { TextInput,Button, StyleSheet, View,Text, ScrollView } from 'react-native';
import {Constants} from 'expo'
let id=0
{/* const Todo = (props) => (
<Text>
{/* <input type='checkbox'
checked={props.todo.checked}
onClick={props.onToggle}
/>
<Button title='delete' button onPress={props.onDelete}></Button>
<Text>{props.todo.text}</Text>
</Text>
) */}
class Todo extends React.Component{
shouldComponentUpdate(nextProps,nextState){
return true
}
render(){
console.log('inside')
return(
<Text>
<Button title='delete' button onPress={props.onDelete}></Button>
<Text>{props.todo.text}</Text>
</Text>
)
}}
export default class App extends React.Component {
constructor(){
super()
this.state={
todos:[],
inputText:'',
update:false
}
}
clearText(){
this.setState({inputText:''})
this.setState({update:true})
}
addTodo(text){
this.setState({update:false})
this.setState({todos: [...this.state.todos,
{ id:id++,
text: text,
checked:false
}
]
})
this.setState({inputText:text})
}
toggle(id){
this.setState({todos: this.state.todos.map(todo=>{
if(id!==todo.id)return todo
return{
id:todo.id,
text:todo.text,
checked: !todo.checked}})})
}
removeTodo(id){
this.setState({todos: this.state.todos.filter(todo=>(todo.id!==id))})
}
render(){
return(
<View style={styles.container}>
<Text >Count of Todos: {this.state.todos.length}</Text>
<Text >{"Todo's checked:"}
{this.state.todos.filter(todo =>(todo.checked===true)).length}</Text>
<TextInput
style={{height:25,borderColor:'red',borderWidth:1,textAlign:'center'}}
value={this.state.inputText}
placeholder={'add Todo'}
onSubmitEditing={()=>{this.clearText()}}
onChangeText={(text) => {this.addTodo(text)}}
/>
<ScrollView>
{this.state.todos.map(todo=>{
<Todo
onToggle={()=>(this.toggle(todo.id))}
onDelete={()=>(this.removeTodo(todo.id))}
todo={todo}
key={todo.id}
/>})}
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
container:{
flex:1,
flexDirection:'column',
height:50,
paddingTop:3*Constants.statusBarHeight,
}
})
You need to return the data from the map in order to render it.
{this.state.todos.map(todo=> (
<Todo
onToggle={()=>(this.toggle(todo.id))}
onDelete={()=>(this.removeTodo(todo.id))}
todo={todo}
key={todo.id}
/>))}
=> {} returns undefined since it is an explicit block, you need to return an implicit block
Here is working code. I modified your code to run on my pc.
import React from 'react';
import {TextInput, Button, StyleSheet, View, Text, ScrollView} from 'react-native';
//import {Constants} from 'expo'
let id = 0
{/* const Todo = (props) => (
<Text>
{/* <input type='checkbox'
checked={props.todo.checked}
onClick={props.onToggle}
/>
<Button title='delete' button onPress={props.onDelete}></Button>
<Text>{props.todo.text}</Text>
</Text>
) */}
class Todo extends React.Component {
shouldComponentUpdate (nextProps, nextState) {
return true
}
render () {
console.log('inside')
return (
<Text>
<Button title='delete' onPress={this.props.onDelete}></Button>
<Text>{this.props.todo.text}</Text>
</Text>
)
}
}
export default class App extends React.Component {
constructor () {
super()
this.state = {
todos: [],
inputText: '',
update: false
}
}
clearText () {
this.setState({inputText: ''})
this.setState({update: true})
}
addTodo (text) {
this.setState({update: false})
this.setState({
todos: [...this.state.todos,
{
id: id++,
text: text,
checked: false
}
]
})
this.setState({inputText: text})
}
toggle (id) {
this.setState({
todos: this.state.todos.map(todo => {
if (id !== todo.id) return todo
return {
id: todo.id,
text: todo.text,
checked: !todo.checked
}
})
})
}
removeTodo (id) {
this.setState({todos: this.state.todos.filter(todo => (todo.id !== id))})
}
render () {
return (
<View style={styles.container}>
<Text >Count of Todos: {this.state.todos.length}</Text>
<Text >{"Todo's checked:"}
{this.state.todos.filter(todo => (todo.checked === true)).length}</Text>
<TextInput
style={{height: 25, borderColor: 'red', borderWidth: 1, textAlign: 'center'}}
value={this.state.inputText}
placeholder={'add Todo'}
onSubmitEditing={() => {this.clearText()}}
onChangeText={(text) => {this.addTodo(text)}}
/>
<ScrollView>
{this.state.todos.map(todo =>
<Todo
onToggle={() => (this.toggle(todo.id))}
onDelete={() => (this.removeTodo(todo.id))}
todo={todo}
key={todo.id}
/>
)}
</ScrollView>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
height: 50,
//paddingTop:3*Constants.statusBarHeight,
paddingTop: 3 * 10,
}
})

react native stack navigation undefined is not an object (evalutating 'props.navigation')

‌‌I'm making an app in react-native and I would like to navigate to different page by clicking on a button using stack navigation:
Here is my code :
app.js
import React from 'react';
import { AppRegistry } from 'react-native';
import { StackNavigator } from 'react-navigation';
import Home from './Screens/Home';
import VideoListItems from './Screens/VideoListItems';
import TrackPlayer from './Screens/TrackPlayer';
const reactNavigationSample = props => {
return <VideoListItems navigation={props.navigation} />;
};
reactNavigationSample.navigationOptions = {
title: "VideoListItems"
};
const AppNavigator = StackNavigator({
Home: { screen: Home, navigationOptions: { header: null }},
VideoListItems: { screen: VideoListItems, navigationOptions: { header: null }},
TrackPlayer: { screen: TrackPlayer, navigationOptions: { header: null }},
}
);
export default class App extends React.Component {
render() {
return (
<AppNavigator />
);
}
}
VideoListItems where the button to navigate is :
import {StackNavigator} from 'react-navigation';
const VideoListItems = ({ video, props }) => {
const { navigate } = props.navigation;
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = video.snippet;
const videoId = video.id.videoId;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
export default VideoListItems;
But I'm getting this error :
TypeError: undefined is not an object (evaluating 'props.navigation')
I don't know how to pass the props navigation and make it able to navigate when clicking on the button, I don't know where is my error, any ideas ?
[EDIT]
My new VideoItemList :
const VideoListItems = props => {
const {
cardStyle,
imageStyle,
contentStyle,
titleStyle,
channelTitleStyle,
descriptionStyle
} = styles;
const {
title,
channelTitle,
description,
thumbnails: { medium: { url } }
} = props.video.snippet;
const videoId = props.video.id.videoId;
const { navigate } = props.navigation;
return(
<View>
<Card title={null} containerStyle={cardStyle}>
<Image
style={imageStyle}
source= {{ uri: url}}
/>
<View style={contentStyle}>
<Text style={titleStyle}>
{title}
</Text>
<Text style={channelTitleStyle}>
{channelTitle}
</Text>
<Text style={descriptionStyle}>
{description}
</Text>
<Button
raised
title="Save And Play"
icon={{ name: 'play-arrow' }}
containerViewStyle={{ marginTop: 10 }}
backgroundColor="#E62117"
onPress={() => {
navigate.navigate('TrackPlayer')
}}
/>
</View>
</Card>
</View>
);
};
This is the file where I display all my components :
import React, { Component } from 'react';
import { View } from 'react-native';
import YTSearch from 'youtube-api-search';
import AppHeader from './AppHeader';
import SearchBar from './SearchBar';
import VideoList from './VideoList';
const API_KEY = 'ApiKey';
export default class Home extends Component {
state = {
loading: false,
videos: []
}
componentWillMount(){
this.searchYT('');
}
onPressSearch = term => {
this.searchYT(term);
}
searchYT = term => {
this.setState({ loading: true });
YTSearch({key: API_KEY, term }, videos => {
console.log(videos);
this.setState({
loading: false,
videos
});
});
}
render() {
const { loading, videos } = this.state;
return (
<View style={{ flex: 1, backgroundColor: '#ddd' }}>
<AppHeader headerText="Project Master Sound Control" />
<SearchBar
loading={loading}
onPressSearch={this.onPressSearch} />
<VideoList videos={videos} />
</View>
);
}
}
And my VideoList where I use VideoListItems :
import React from 'react';
import { ScrollView, View } from 'react-native';
import VideoListItems from './VideoListItems';
const VideoList = ({ videos }) => {
const videoItems = videos.map(video =>(
<VideoListItems
key={video.etag}
video={video}
/>
));
return(
<ScrollView>
<View style={styles.containerStyle}>
{videoItems}
</View>
</ScrollView>
);
};
const styles = {
containerStyle: {
marginBottom: 10,
marginLeft: 10,
marginRight: 10
}
}
export default VideoList;
That's because you try to extract navigation from a prop named props (that doesn't exist), you have many ways to solve this problem :
Use the rest operator to group all props except video inside a props variable
const VideoListItems = ({ video, ...props }) => {
Don't destructure you props object
const VideoListItems = props => {
// don't forget to refactor this line
const videoId = props.video.id.videoId;
Extract navigation from props
const VideoListItems = ({ video, navigation }) => {
const { navigate } = navigation;

Trying to get the modal working in React Native

Attempting to get the modal working on my react native app. I want the more page to display a modal of more options. I have made the following attempt in regards putting the modal in the more menu page. The error I am currently getting is:
MoreMenu.js
import React, { Component } from 'react';
import { Modal, Text, TouchableHighlight, View } from 'react-native';
class MoreMenu extends Component {
state = {
modalVisible: false,
}
setModalVisible(visible) {
this.setState({modalVisible: visible});
}
render() {
return (
<View style={{marginTop: 22}}>
<Modal
animationType={"slide"}
transparent={false}
visible={this.state.modalVisible}
onRequestClose={() => {alert("Modal has been closed.")}}
>
<View style={{marginTop: 22}}>
<View>
<Text>Hello World!</Text>
<TouchableHighlight onPress={() => {
this.setModalVisible(!this.state.modalVisible)
}}>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
<TouchableHighlight onPress={() => {
this.setModalVisible(true)
}}>
<Text>Show Modal</Text>
</TouchableHighlight>
</View>
);
}
}
TabsRoot.JS
class Tabs extends Component {
_changeTab (i) {
const { changeTab } = this.props
changeTab(i)
}
_renderTabContent (key) {
switch (key) {
case 'today':
return <Home />
case 'share':
return <Share />
case 'savequote':
return <SaveQuote />
case 'moremenu':
return <MoreMenu />
}
}
render () {
const tabs = this.props.tabs.tabs.map((tab, i) => {
return (
<TabBarIOS.Item key={tab.key}
icon={tab.icon}
selectedIcon={tab.selectedIcon}
title={tab.title}
onPress={() => this._changeTab(i)}
selected={this.props.tabs.index === i}>
{this._renderTabContent(tab.key)}
</TabBarIOS.Item>
)
})
return (
<TabBarIOS tintColor='black'>
{tabs}
</TabBarIOS>
)
}
}
export default Tabs
You forget to export MoreMenu Component. and you use MoreMenu Component in TabsRoot.js.
pls add following line at the end of MoreMenu.js
export default MoreMenu