React native not passing props between components? - javascript

I have a simple container component that should handle some logic at some point:
import React, {Component} from 'react';
import {Text, View, Button, Image} from 'react-native';
import Title from '../Presentational/Title';
class AppList extends React.Component {
render() {
return (
<Title titleProperty={'To Do Something'}></Title>
);
}
}
export default AppList;
I try to pass some props to a Title component so that component would display them:
import React, {Component} from 'react'
import {View, Text, StyleSheet} from 'react-native'
export default class Title extends React.Component {
render() {
const {children} = this.props.titleProperty;
return (
<View style = {styles.header}>
<Text style={styles.title}>{children}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
header: {
backgroundColor: 'skyblue',
padding: 15,
},
title: {
textAlign: 'center',
color: 'white',
},
})
The result I'm getting is a blue bar without any text
imgur link
Why is it not working?

The reason it is not working is because in Title.js you are trying to get value of titleProperty incorrectly.
const {children} = this.props.titleProperty; implies that you want to store value of this.props.titleProperty.children inside children constant.
what you should do is read value of titleProperty and then it will it display correctly in your component.
You can do this in various ways, few of them are listed below
const children = this.props.titleProperty;
const { titleProperty } = this.props;
In the first option you can read titleProperty from props and assign it to any named variable you want. In the later option it will read the value of key from this.props and only assign the value of key is present otherwise undefined
Find output here

The problem is this line:
const {children} = this.props.titleProperty;
In this way you're trying to deconstruct the titleProperty which should be an object and should have the children property.
More about destructuring on MDN
I am not sure if you are confused with the children props of React, in this case I recommend you to read this answer: https://stackoverflow.com/a/49706920/9013688

Related

React native call functions and change states from a component

So I currently have a function that renders a component NewButton, in that component, how do I call the function toggleModalVisibility, which is defined outside of that component? That function will change many states and call other functions, and change rendering as well.
import React, { useState, useEffect} from 'react'
import {Button, View, Text, StyleSheet,TextInput,ScrollView, Modal} from 'react-native'
import { BottomSheet } from 'react-native-btr';
import NewButton from './NewButton'
export default function CardFolder({navigation, navigation: {setOptions}}){
const [visible, setVisible] = useState(false);
//many other states
const toggleModalVisibility = () => {
//changes states, calls other functions, change rendering, Toggle bottomSheet
};
return(
< >
<Modal> modal containing a text field, change states </Modal>
<BottomSheet>contains other options, upload something to db</BottomSheet>
<View style = {{flex:1}}>
<NewButton style = {{bottom: 50}} />
</View>
</>
)
}
The Component:
import {View, Button} from 'react-native'
export default class NewButton extends React.Component {
return(
<View style = {[styles.container,this.props.style]}>
//how do I call the functon toggleModalVisibility here?
<Button onPress={toggleModalVisibility}/>
</View>
)
}
}
you can add it as a prop to NewButton Component
<NewButton style={{bottom: 50}} toggleModalVisibility={toggleModalVisibility} />
and the call it like
<Button onPress={this.props.toggleModalVisibility}/>
As #Krosf suggested you, you should pass the function by props and then call the function when Button is pressed, in your case you are using class component, so you should use the "this" keyword in order to access your "NewButton props"
like this:
<Button onPress={ this.props.toggleModalVisibility } />

How to loop in MasonryList on React Native?

I want to use MasonryList component in my react native project.
So i created a component like this below:
import React, {Component} from 'react';
import {Image, StyleSheet, View, TouchableOpacity, Alert} from 'react-native';
import MasonryList from 'react-native-masonry-list';
import {books} from '../assets';
class Books extends Component {
render() {
return (
<View style={styles.container}>
<MasonryList source={[{
uri: '...'
}]} />
</View>
);
}
}
so, "uri" prop expects a link for a single image, if you want to use multiple images you should have a structure like this.
{ uri: "link" }, {uri: "link2"}, {uri: "link3" }
and so on...
I have imported the books, so my question is how can i loop in the components itself, to reach each element's "thumbnail" to get the url on the structure below?
my books.js file structure is like:
export default {
items: [
{
kind: "books#volume",
id: "md5"
volumeInfo: {
imageLinks: {
thumbnail: "
Simply i could do mapping in the render function and create MasonryList component but that would create the component as much as the loop counts. I want only 1 component and multiple uri links in it.
You can use a state array in "source" prop and in componentDidMount or at any relevant location, set this state using map function.
import React, {Component} from 'react';
import {Image, StyleSheet, View, TouchableOpacity, Alert} from 'react-native';
import MasonryList from 'react-native-masonry-list';
import {books} from '../assets';
class Books extends Component {
constructor(props){
super(props);
this.state={
imageArray: [],
}
}
componentDidMount(){
var imageArray = [];
books.map(book =>{
imageArray.push({uri: book.volumeInfo.imageLinks.thumbnail})
});
this.setState({imageArray});
}
render() {
const {imageArray} = this.state;
return (
<View style={styles.container}>
<MasonryList source={imageArray} />
</View>
);
}
}

How to turn an Object (data from database) into an array and show one of its keys on the simulator

So I am trying to render my Firebase Database onto my Android simulator and it is showing an error, in which the solution is to convert an object into an array, but I do not know-how.
import _ from 'lodash';
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {FlatList, View, Text} from 'react-native';
import {employeesFetch} from '../actions';
import ListItem from './ListItem';
class EmployeeList extends Component {
componentDidMount(){
this.props.employeesFetch();
}
renderRow(employee) {
return <ListItem employee={employee}/>;
};
render(){
console.log(this.props.employees);
return (
<View>
<FlatList
data={Object.keys(this.props.employees)}
renderItem={this.renderRow}
/>
</View>
);
}
}
const mapStateToProps = state => {
const employees = _.map(state.employees, (val, uid) => {
return { ...val, uid };
});
return { employees };
};
export default connect(mapStateToProps, { employeesFetch })(EmployeeList);
That mapStateToProps helper is supposed to create a variable called employees (if I am not wrong, I am just learning to code) but when I write that down like this:
<FlatList
data=employees
renderItem={this.renderRow}
/>
It says that employees is not defined. Just in case, I will add the ListItem file to show what I have done there.
import React, {Component} from 'react';
import {Text} from 'react-native';
import {CardSection} from './common';
class ListItem extends Component {
render () {
const { name } = this.props.employee;
return (
<CardSection>
<Text style={styles.titleStyle}>
{name}
</Text>
</CardSection>
);
}
}
export default ListItem;
I expect the output to be a list showing the employees (recorded in Firebase Database) on the screen, but is showing an error: Invariant Violation: Objects are not valid as a React child (found: object with keys {name, phone, shift, uid}). If you meant to render a collection of children, use an array instead.

React Native : Why is "navigation" not being passed to my component?

I have been working on this problem for two days now and nothing on the web seems to be exactly what I am looking for.
I am attempting to implement a StackNavigator into my React Native app, but for some reason "navigation" is not being passed as a prop to the involved components. Therefore when I call this.props.navigation.navigator by pressing Button, I get the error undefined is not an object (evaluating this.props.navigation.navigate).
I have logged the props several times and the props object is empty, so the issue is not a deconstruction-of-the-props-object issue like others who get this error have had, but the fact that the navigation prop is not there in the first place.
I've tried placing the navigator code in its own file and in the App.js file thinking that it was somehow called after the components are rendered, and therefore not getting a chance to pass the navigation prop in, but that didn't work either. I've also looked to see if it is part of the props in the componentDidMount event. Still not.
import React, { Component } from 'react'
import { Text, View, Button, StyleSheet, FlatList } from 'react-native'
import { StackNavigator } from 'react-navigation'
import { getDecks } from '../utils/api'
import NewDeckView from './NewDeckView'
import DeckListItem from './DeckListItem'
export default class DeckListView extends Component {
constructor(props){
super(props)
this.state = {
decks: []
}
}
componentDidMount(){
console.log('props now test',this.props)
getDecks()
.then( result => {
const parsedResult = JSON.parse(result);
const deckNames = Object.keys(parsedResult);
const deckObjects = [];
deckNames.forEach( deckName => {
parsedResult[deckName].key = parsedResult[deckName].title
deckObjects.push(parsedResult[deckName])
})
this.setState({
decks:deckObjects
})
} )
}
render(){
return (
<View style={styles.container}>
<Text style={styles.header}>Decks</Text>
<FlatList data={this.state.decks} renderItem={({item})=><DeckListItem title={item.title} noOfCards={item.questions?item.questions.length:0}/>} />
<Button styles={styles.button} title="New Deck" onPress={()=>{this.props.navigation.navigate('NewDeckView')}}/>
</View>
)
}
}
const styles = StyleSheet.create({
header:{
fontSize:30,
margin:20,
},
container:{
flex:1,
justifyContent:'flex-start',
alignItems:'center'
},
button:{
width:50
}
})
const Stack = StackNavigator({
DeckListView : {
screen: DeckListView,
},
NewDeckView: {
screen:NewDeckView,
}
})
Like Vicky and Shubhnik Singh mentioned, you need to render the imported navigation stack in App.js like so:
import React from 'react';
import { Stack } from './navigator/navigator'
export default class App extends React.Component {
render() {
return <Stack/>
}
}
The navigator should look something like this and the first key in the object passed to StackNavigator will be rendered by default. In this case, it will be DeckListView.
import { StackNavigator } from 'react-navigation'
import DeckListView from '../components/DeckListView'
import NewDeckView from '../components/NewDeckView'
export const Stack = StackNavigator({
DeckListView : {
screen: DeckListView,
navigationOptions: {
headerTitle: 'Home',
},
},
NewDeckView: {
screen:NewDeckView,
navigationOptions: {
headerTitle: 'New Deck',
},
},
})
Thanks guys for the support! Somehow this wasn't clear for me in the documentation.

How to implement ListView in ReactNative with custom cell component?

I am building a ReactNative + Redux app and am using the ListView component.
In _renderRow() of the ListView, I'd like to return my own cell component (called JobDetailCell that only receives the data in its props from the component that is managing the ListView (called JobsRootComponent).
I came up with the following code so far:
JobsRootComponent.js
import React, {
Component,
StyleSheet,
Text,
View,
ListView,
ActivityIndicatorIOS,
NavigatorIOS,
TouchableHighlight
} from 'react-native'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { fetchJobs } from '../actions/Actions'
import { JobDetailCell } from './JobDetailCell'
import { JobDetailComponent } from './JobDetailComponent'
class JobsRootComponent extends Component {
...
_renderRow(rowData) {
const title = rowData.title
const subtitle = rowData.by
return (
<JobDetailCell title={title} subtitle={subtitle}></JobDetailCell>
)
}
...
render() {
return (
<ListView
style={styles.container}
dataSource={this.props.dataSource}
renderRow={this._renderRow}
/>
)
}
...
}
JobDetailCell.js
import React, {
Component,
StyleSheet,
Text,
View,
} from 'react-native'
export default class JobDetailCell extends Component {
render() {
return (
<View style={styles.cellContainer}>
<Text style={styles.cellTitle}>{this.props.title}</Text>
<Text style={styles.cellSubtitle}>{this.props.subtitle}</Text>
</View>
)
}
}
However, when I am running the app, I get the following errors in the chrome dev console:
ExceptionsManager.js:76 Warning:
React.createElement: type should not
be null, undefined, boolean, or number. It should be a string (for DOM
elements) or a ReactClass (for composite components). Check the render
method of StaticRenderer.
Can someone tell me what I am doing wrong here?
The problem is that you are importing your components in the wrong way.
This line
import { JobDetailCell } from './JobDetailCell'
Is equivalent to this line:
var JobDetailCell = require('./JobDetailCell').JobDetailCell;
Which gets undefined since you exported the component itself, which has no field named JobDetailCell.
This is how you should import your component:
import JobDetailCell from './JobDetailCell'

Categories