Lately i've been trying to link my js on component folder but suddenly the issue came out. The first issue is referrence error which occurs because i make typo mistakes on import section. But then ,on 2nd trial by running the emulator i got 'Type Error: Undefined is not an object (props.albums.title)'
Here's my Card.js
import React from 'react';
import { View } from 'react-native';
const Card = (props) => {
return (
<View style={styles.containerStyle}>
{props.children}
</View>
);
};
const styles = {
containerStyle: {
borderWidht: 1,
borderRadius: 2,
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTOp: 10
}
};
export default Card;
here is the AlbumDetail
import React from 'react';
import { Text } from 'react-native';
import Card from './Card';
const AlbumDetail = (props) => {
return (
<Card>
<Text>{props.album.title}</Text>
</Card>
);
};
export default AlbumDetail;
here is the AlbumList
import React, { Component } from 'react';
import { View } from 'react-native';
import axios from 'axios';
import AlbumDetail from './AlbumDetail';
class AlbumList extends Component {
state={ albums: [] };
componentWillMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(response => this.setState({ albums: response.data }));
}
renderAlbums() {
return this.state.albums.map(album => <AlbumDetail key={album.title} record={album} />);
}
render() {
console.log(this.state);
return (
<View>
{this.renderAlbums()}
</View>
);
}
}
export default AlbumList;
You must catch the error 'undefined' which is generated by the array.You declare empty array in state.
renderAlbums(){
if(this.state.albums=='undefined'){
//handle Error
}else{
return this.state.albums.map(album => <AlbumDetail key={album.title} record={album} />)
}
Related
To put in context I am building an app as an exercise in a course to program in react native and we are learning Redux
For me everything is fine but I have doubts in two parts in the index of the scene where the application is seen in this case welcome / index.js there is a line that is for 'useSelector' and another is in the reduce of recipe that if the data is well linked because it throws me an error.
"ERROR TypeError: undefined is not an object (evaluating 'store.getState')"
I share the different components of the redux.
Everything is in a store folder and everything is modulated
store/reduce
store/reduce/index.js
import { combineReducers, createStore } from "redux";
import { recipesReducer } from "./reducer";
const rootReducer = combineReducers({
recipes: recipesReducer
});
export default createStore(rootReducer);
store/reducer/recipes.reducer.js
import {recipeTypes} from '../types';
import {recipes} from '../../data';
const { SELECT_RECIPE } = recipeTypes;
const initialState = {
recipes: recipes,
selectedRecipe: null
}
const recipesReducer = (state = initialState, action) => {
switch(action.type) {
case SELECT_RECIPE:
const indexRecipe = state.recipes.findIndex(
(recipe) => recipe.id === action.recipeId
);
if(indexRecipe === -1) return state;
return {
...state,
selectedRecipe: state.recipes[indexRecipe]
}
default:
return state;
}
}
export default recipesReducer;
store/reduce/index.js
export {default as recipesReducer} from './recipes.reducer';
store/types/index.js
export * from './recipes.types';
store/types/recipes.type.js
export const recipeTypes = {
SELECT_RECIPE: 'SELECT_RECIPE',
}
store/action/recipes.action.js
import { recipeTypes } from '../types';
const { SELECT_RECIPE } = recipeTypes;
export const selectRecipe = (id) => {
return {
type: SELECT_RECIPE,
recipeId: id,
};
}
store/action/index.js
export * from './repice.action';
welcome/index
import {Button, CardsRecipes, MenuAlt, Pickers, TT} from '../../components';
import { FlatList, StyleSheet, Text, View } from 'react-native';
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Color from '../../constants/colors';
import { recipe } from '../../data';
import { selectRecipe } from '../../store/action';
const Welcome= ({navigation, route}) => {
const dispatch = useDispatch();
const recipe = useSelector(state => state.recipe.recipe);
const onSelected = (item) => {
dispatch(selectRecipe(item.id));
navigation.navigate('Recipe');
}
const renderItem = ({item}) => <CardsRecipes item={item} onSelected={onSelected(item)} />
return (
<View style={styles.container}>
<MenuAlt title = {'Recetas'} />
<View style={styles.textContainer}>
<Text style= {styles.text}>Bienvenido a la App de Recetas de Cocina</Text>
</View>
<View style = {styles.buttonContainer}>
</View>
<FlatList
data= {recipe}
renderItem = {renderItem}
keyExtractor = {item => item.id}
/>
</View >
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Color.primary,
color: Color.letter,
fontFamily: 'Lato-Regular',
},
textContainer: {
alignItems: 'center',
justifyContent: 'center',
},
text: {
color: Color.letter,
fontSize: 20,
fontWeight: 'bold',
marginTop: 10,
marginBottom: 10,
},
buttonContainer: {
width: '100%',
alignItems: 'center',
marginTop: 10,
marginBottom: 10,
height: 33,
},
});
export default Welcome;
app.js
import {ActivityIndicator, StyleSheet, View} from 'react-native';
import React, { useState } from 'react';
import AppNavigator from './navigation';
import Color from './constants/colors';
import { Provider } from 'react-redux';
import { StatusBar } from 'expo-status-bar';
import { store } from './store';
import { useFonts } from 'expo-font';
export default function App() {
//useState
const [selected, setSelected] = useState(false);
const [order, setOrder] = useState([]);
//funciones
const [loaded] = useFonts({
'Lato-Regular': require('./assets/fonts/Lato-Regular.ttf'),
'Lato-Bold': require('./assets/fonts/Lato-Bold.ttf'),
'Lato-Light': require('./assets/fonts/Lato-Light.ttf'),
'Lato-Italic': require('./assets/fonts/Lato-Italic.ttf'),
'Lato-Black': require('./assets/fonts/Lato-Black.ttf'),
});
if(!loaded) {
return (
<View style={styles.containerLoader}>
<ActivityIndicator size="large" color={Color.letter} />
</View>
)
}
const onSelectedEnlarge = ( select, order ) => {
setOrder(order)
setSelected(select);
};
/*
let content = <Super onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
if (!selected) {
content = <Super onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
}
else
{
content = <ListSuper onSelectedEnlarge={onSelectedEnlarge} object = {order}/>;
}
*/
return (
<Provider store={store}>
<AppNavigator/>
</Provider>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Color.primary,
color: Color.letter,
fontFamily: 'Lato-Regular',
},
});
thanks for your help
How can I send props to another file?
I have a component file. And there is an array where data are pushed. If the user click ok, then I want the array to another file.
example:
sizeComponent.js
import React from 'react';
import { StyleSheet, View, Text, TouchableOpacity, FlatList, Dimensions } from 'react-native';
import pure from 'recompose/pure';
const width = Dimensions.get('window').width;
const height = Dimensions.get('window').height;
const AboveSize = ({ data, onPress }) => {
return (
<View style={{marginTop: 10}}>
<Text style={{color: '#333', fontSize: 16}}>Bekleidungsgröße</Text>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
<FlatList
data={data}
keyExtractor={item => item.key}
horizontal
getItemLayout={(data, index) => {
return {
index,
length: 200,
offset: height * index
}
}}
showsHorizontalScrollIndicator={false}
renderItem={({ item }) => {
return (
<TouchableOpacity onPress={onPress} style={{borderWidth: 1, borderColor: '#ccc', justifyContent: 'center', alignItems: 'center', borderRadius: 8, height: 77, width: 77, margin: 12, marginLeft: 0, backgroundColor: data.includes(item.size) ? 'red' : 'blue'}}>
<Text style={{color: data.includes(item.size) ? '#fff' : '#333', fontSize: 20}}>{item.size}</Text>
</TouchableOpacity>
)
}}
/>
</View>
</View>
)
};
export default pure(AboveSize);
Main.js
import SizeComponent from 'sizeComponent';
/* Size from Mock Data */
const productData = [
{
item: {
id: 1,
name:"Calvin Klein Bag",
price:"29.99€",
size: [
{
key: "1",
size: "XS"
},
{
key: "2",
size: "S",
},
{
key: "3",
size: "M"
},
{
key: "4",
size: "L"
},
{
key: "5",
size: "XL"
},
{
key: "6",
size: "XXL"
},
{
key: "7",
size: "XXXL"
}
],
}
}];
const [productSize, setProductSize] = useState([]);
...
<SizeComponent data={productData} onPress={() => console.log('I want here the data from the component file which was selected')}
In the sizeComponent.js change the onPress method to the following code:
<TouchableOpacity onPress={()=>onPress(item)}
so when the onPress is called the selected item will be passed to the callback method which you can access like this
<SizeComponent data={productData} onPress={(item) => {//the seleteced item will be accessible here })
React Native applications are built using components that manage state internally.
To globalize your state there is a state management libraries like Redux exist to solve this issue. Redux provides a central location for all the states of an application where each component can access the values stored in the state.
reducer.js
import { combineReducers } from "redux";
const INITIAL_STATE = { table:[] };
const reducers = (state = INITIAL_STATE, action) => {
switch (action.type) {
case "PUSH_TABLE":
state.table.push(action.value)
return { ...state, table: state.table };
default:
return state;
}
};
export default combineReducers({ reducers: reducers });
action.js
export const pushTable = (title) => ({
type: "PUSH_TABLE",
value: title
});
app.js
import React from "react";
import ListScreen from "./src/ListScreen";
import ModalScreen from "./src/ModalScreen";
import { NavigationContainer } from "#react-navigation/native";
import { createStackNavigator } from "#react-navigation/stack";
import { Provider } from "react-redux";
import { createStore } from "redux";
import reducer from "./src/reducer";
const store = createStore(reducer);
const Stack = createStackNavigator();
function MainStackNavigator() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="List" component={ListScreen} />
<Stack.Screen name="Modal" component={ModalScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default function App() {
return (
<>
<Provider store={store}>
<MainStackNavigator />
</Provider>
</>
);
}
Table.js
import React from "react";
import { Button } from "react-native";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import { pushTable } from "./action";
class Table extends React.Component {
render() {
return (
<>
<Button
title={"PUSH TABLE"}
onPress={() => this.props.pushTable("NICE") }
/>
{this.props.reducers.table.map((cel, index) => (
<Text>{cel} {index}</Text>
))}
</>
);
}
}
const mdtp = (dispatch) => bindActionCreators( { pushTable, }, dispatch );
const mtp = (state) => {
const { reducers } = state;
return { reducers };
};
export default connect(mtp, mdtp)(Table);
I am trying to use ListView on my js page and I am getting no data on my screen. The screen is totally blank. Below is the image of the empty screen. I am getting a warning.
Below is my code where I am calling the ListView:
import React, { Component } from 'react';
import { Text, View, StyleSheet, ListView } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux'
import reducers from '../reducers/ServiceReducer';
import ServiceItem from './ServiceItem';
const styles = StyleSheet.create({
container: {
flex: 1,
width: 353,
flexWrap: 'wrap',
paddingTop: 20,
paddingLeft: 20,
},
});
const store = createStore(reducers);
class AutoCompActivity extends Component {
componentWillMount() {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
});
this.dataSource = ds.cloneWithRows(this.props.services);
}
render() {
return (
<Provider store={store}>
<View style={styles.container}>
<ListView
enableEmptySections={true}
dataSource={this.dataSource}
renderRow={(rowData) =>
<ServiceItem services={rowData} />
}
/>
</View>
</Provider>
);
}
}
const mapStateToProps = state => {
return { services: state.services };
};
const ConnectedAutoCompActivity = connect(mapStateToProps)(AutoCompActivity);
const app1 = () => (
<Provider store={store}>
<ConnectedAutoCompActivity />
</Provider>
)
export default app1;
My ServiceItem.js file is below:
import React from 'react';
import { StyleSheet, Text, View, Button, ImagePropertiesAndroid } from 'react-native';
import {connect} from 'react-redux';
import { getTheme } from 'react-native-material-kit';
import Icon from 'react-native-vector-icons/EvilIcons';
import * as actions from '../actions';
const theme = getTheme();
const styles = StyleSheet.create({
card: {
marginTop: 20,
},
title: {
top: 20,
left: 80,
fontSize: 24,
},
image: {
height: 100,
},
action: {
backgroundColor: 'black',
color: 'white',
},
icon: {
position: 'absolute',
top: 15,
left: 0,
color: 'white',
backgroundColor: 'rgba(255,255,255,0)',
},
});
const ServiceItem=(props)=>{
return(
<View>
<Text style={[theme.cardTitleStyle, styles.title]}>{props.services.services}</Text>
</View>
)
}
export default connect(null, actions)(ServiceItem);
My Json file is very simple:
[
{
"services": "Test1"
},
{
"services": "Test2"
},
{
"services": "Test3"
},
{
"services": "Test4"
},
{
"services": "Test4"
}
]
My service.Reducer has the following code:
import services from './services.json';
const initialState = {
services
};
export default (state = initialState, action) => {
switch (action.type) {
default:
return state;
}
}
I checked my code several times and could not find any issue. I also installed react redux. Store is defined as const in my code. I am just trying to show each service as
test1,
test2 on my phone
Any help will be greatly appreciated.
The problem here is that you are using Provider inside connected component.
The connected component should be wrapped inside <Provider>. Replace your code with the following and it will work as expected.
import React, { Component } from 'react';
import { Text, View, StyleSheet, ListView } from 'react-native';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux'
import reducers from '../reducers/ServiceReducer';
import ServiceItem from './ServiceItem';
const styles = StyleSheet.create({
container: {
flex: 1,
width: 353,
flexWrap: 'wrap',
paddingTop: 20,
paddingLeft: 20,
},
});
const store = createStore(reducers);
class AutoCompActivity extends Component {
componentWillMount() {
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
});
this.dataSource = ds.cloneWithRows(this.props.services);
}
render() {
return (
<Provider store={store}>
<View style={styles.container}>
<ListView
enableEmptySections={true}
dataSource={this.dataSource}
renderRow={(rowData) =>
<ServiceItem services={rowData} />
}
/>
</View>
</Provider>
);
}
}
const mapStateToProps = state => {
return { services: state.services };
};
const ConnectedAutoCompActivity = connect(mapStateToProps)(AutoCompActivity);
const App = () => (
<Provider store={store}>
<ConnectedAutoCompActivity />
</Provider>
)
export default App;
Currently, I have a simple React Native Expo app setup. I have two components App and QRreader.
I am trying to import the QRreader component into my main App component.
The Main App component code...
import React, { Component } from 'react';
import { Button, Text, View, StyleSheet } from 'react-native';
import { Constants, WebBrowser } from 'expo';
import QRreader from './qr';
export default class App extends Component {
state = {
result: null,
};
render() {
return (
<View style={styles.container}>
<QRreader/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
The QR component code...
import React, { Component } from 'react';
import { Text, View, StyleSheet, Alert } from 'react-native';
import { Constants, BarCodeScanner, Permissions } from 'expo';
export default class QRreader extends Component {
state = {
hasCameraPermission: null
};
componentDidMount() {
this._requestCameraPermission();
}
_requestCameraPermission = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted',
});
};
_handleBarCodeRead = data => {
Alert.alert(
'Scan successful!',
JSON.stringify(data)
);
};
render() {
return (
<View style={styles.container}>
{this.state.hasCameraPermission === null ?
<Text>Requesting for camera permission</Text> :
this.state.hasCameraPermission === false ?
<Text>Camera permission is not granted</Text> :
<BarCodeScanner
onBarCodeRead={this._handleBarCodeRead}
style={{ height: 200, width: 200 }}
/>
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
}
});
I tried different variations of the import using "./" "." "qr.js" "qr"
Im getting an error Unable to resolve module "qr.js" Module does not exist in the main module map.
My file structure is Here
You haven't registered your main module yet.
AppRegistry.registerComponent('Main', () => App); Please add this line to the bottom of your class and check if the problem persists.
hmm...so it looked like I had to restart the Expo project for it to work without adding any additional code.
Just out of curiosity?
Where would I add AppRegistry.registerComponent('Main', () => App); exactly? and why would I have to do this?
I am trying to scaffold a simple drawer and navigation in react-native.
As you can see I import the drawer and then I instantiate the Navigator below the Toolbar.
I want to be able to change the route from the AppDrawer but the only thing I get after the button click is
*undefined is not a function (evaluating '_this2.props.navigator.push({ id: 'component5' })') *
Note: I have not attached Component 3 or 5 code because they are simple text renders.
index.android.js
import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Text, View, Navigator, ToolbarAndroid} from 'react-native';
import Component3 from "./app/components/Component3/Component3";
import Component5 from "./app/components/Component5/Component5";
import MyAppDrawer from "./app/components/Miscellaneous/AppDrawer";
import Drawer from 'react-native-drawer';
const drawerStyles = {
drawer: {
shadowColor: "#343477",
shadowOpacity: 0.8,
shadowRadius: 0,
}
}
export default class ReactTest extends Component {
constructor(props, context) {
super(props, context);
this.state = {
drawerType: 'overlay',
openDrawerOffset: 50,
closedDrawerOffset: 0,
panOpenMask: .1,
panCloseMask: .9,
relativeDrag: false,
panThreshold: .25,
tweenHandlerOn: false,
tweenDuration: 350,
tweenEasing: 'linear',
disabled: false,
tweenHandlerPreset: null,
acceptDoubleTap: false,
acceptTap: false,
acceptPan: true,
tapToClose: false,
negotiatePan: false,
rightSide: false,
};
}
openDrawer() {
this.drawer.open()
}
renderScene(route, navigator) {
switch (route.id) {
case 'component2':
return (<Component2 navigator={navigator}/>)
case 'component3':
return (<Component3 navigator={navigator}/>)
case 'component4':
return (<Component4 navigator={navigator}/>)
case 'component5':
return (<Component5 navigator={navigator} title="component5"/>)
case 'component6':
return (<Component6 user={route.user} navigator={navigator} title="component6"/>)
}
}
onActionSelected(position) {
console.log("Settings clicked");
}
onIconClicked(position) {
console.log("App Drawer clicked");
}
render() {
var controlPanel = <MyAppDrawer navigator={navigator} closeDrawer={() => {
this.drawer.close();
}}/>
return (
<View style={styles.containerToolbar}>
<Drawer
ref={c => this.drawer = c}
type={this.state.drawerType}
animation={this.state.animation}
captureGestures={true}
openDrawerOffset={this.state.openDrawerOffset}
closedDrawerOffset={this.state.closedDrawerOffset}
panOpenMask={this.state.panOpenMask}
//panCloseMask={this.state.panCloseMask}
relativeDrag={this.state.relativeDrag}
panThreshold={this.state.panThreshold}
content={controlPanel}
styles={drawerStyles}
disabled={this.state.disabled}
// tweenHandler={this.tweenHandler.bind(this)}
// tweenDuration={this.state.tweenDuration}
// tweenEasing={this.state.tweenEasing}
acceptDoubleTap={this.state.acceptDoubleTap}
acceptTap={this.state.acceptTap}
acceptPan={this.state.acceptPan}
tapToClose={this.state.tapToClose}
negotiatePan={this.state.negotiatePan}
// changeVal={this.state.changeVal}
side={this.state.rightSide ? 'right' : 'left'}
>
<ToolbarAndroid
style={styles.toolbar}
title="MyApp"
// logo={require('./dummy_logo.png')}
navIcon={require("./navigation_icon.png")}
onActionSelected={this.onActionSelected}
onIconClicked={this.openDrawer.bind(this)}
titleColor="black"
actions={[
{title: "Log out", show: "never"}
]}
/>
<Navigator
style={styles.container}
initialRoute={{id: 'component3'}}
renderScene={this.renderScene}/>
</Drawer>
</View>
);
}
}
const styles = StyleSheet.create({
containerToolbar: {
flex: 1,
//justifyContent: 'center',
justifyContent: 'flex-start',
// https://github.com/facebook/react-native/issues/2957#event-417214498
alignItems: 'stretch',
backgroundColor: '#F5FCFF',
},
toolbar: {
backgroundColor: '#e9eaed',
height: 56,
},
});
AppRegistry.registerComponent('ReactTest', () => ReactTest);
AppDrawer.js
import React, {Component} from 'react';
import {View, Text, Button, Navigator} from 'react-native';
import styles from './styles';
export default class AppDrawer extends Component {
constructor() {
super();
}
render() {
return (
<View style={styles.controlPanel}>
<Text style={styles.controlPanelWelcome}>
Control Panel
</Text>
<Button
onPress={() => {
console.log("pressed");
this.props.navigator.push({
id: 'component5',
});
}}
title="Component 5"
/>
</View>
)
}
}
Since you don't have MyAppDrawer inside your renderScene function, you don't have access to the navigator. You would need to add a ref and use that to get the navigator:
Add ref={navigator => this.navigator = navigator} to your Navigator component, then you can do
<MyAppDrawer navigator={this.navigator} closeDrawer={() => {
this.drawer.close();
}}/>