How to implement ListView in ReactNative with custom cell component? - javascript

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'

Related

React Native, onPress not firing

Cannot get any output from my function test() which I have written in Boxes.js when I add onPress={test} to my View tag in Dice.js.
I have tried to add test() on tags like Text, then it works, but not when I put it on the View tag.
Boxes.js:
import react from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import Dice from "./Dice";
import PatternDivider from "./PatternDivider";
export function test() {
console.log("hi");
}
export default class Boxes extends react.Component {
render() {
return (
<View style={styles.box}>
<Text style={styles.header}>Advice #117</Text>
<Text style={styles.advice}>
It is easy to sit up and take notice, what's difficult is getting uu
and taking action
</Text>
<PatternDivider />
<Dice />
</View>
);
}
}
Dice.js:
import react from "react";
import { StyleSheet, Text, View, Image } from "react-native";
import { test } from "./Boxes";
export default class Dice extends react.Component {
render() {
return (
<View style={styles.circle} onPress={test}>
<Image
source={require("../assets/icon-dice.png")}
style={styles.dice}
/>
</View>
);
}
}
If you wanna Dice to be clickable, use one the components that handles press events, like Pressable. Not all components accept an onPress property, View is one of them.
import react from "react";
import { StyleSheet, Text, View, Image, Pressable } from "react-native";
import { test } from "./Boxes";
export default class Dice extends react.Component {
render() {
return (
<Pressable style={styles.circle} onPress={test}>
<Image
source={require("../assets/icon-dice.png")}
style={styles.dice}
/>
</Pressable>
);
}
}
React Native's View component doesn't have an onPress property https://reactnative.dev/docs/view

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.

How to fix error when working with Calendar Component of react-date-range

I am working with Calendar component of react-date-range but I have seen following error.
This is simple code I using.
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import { Calendar } from 'react-date-range';
export default class App extends Component {
handeeSelect(date) {
console.log(date);
}
render() {
return (
<View>
<Calendar
onInit={this.handeeSelect}
onChange={this.handeeSelect}
/>
</View>
);
}
}
How to fix it?
Edit: As mentioned in the comments, the issue revolved around the library in use. Either the linking to the Native code or the library was causing compatibility issues. Be sure to link libraries you add to native code when adding new ones.
I think you need to wrap the calendar component in a div because React-Native View is weird and needs a child element.
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import { Calendar } from 'react-date-range';
export default class App extends Component {
handeeSelect(date) {
console.log(date);
}
render() {
return (
<View>
<div>
<Calendar onInit={this.handeeSelect} onChange={this.handeeSelect} />
</div>
</View>
);
}
}

Error : Forgot to export your Listview item component

This is the error i'm getting.
Warning: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in. Check your code at
BookingPage.js:19.
I have a Listview and item component is imported properly. When i'm changing export of Listview item from
export default connect(mapStateToProps, {callCancel, setBookingstatus})(BookingCard);
to
export {BookingCard};
it's working. but i want to use redux for Listview item component. how to export class correctly. This is my BookingCard (Listview item component)
import React from 'react';
import {View, Text, StyleSheet, TouchableOpacity} from 'react-native';
import { connect } from 'react-redux';
import {Icon, Button} from 'native-base';
import {callCancel, setBookingstatus} from '../actions';
class BookingCard extends React.Component {
render() {
return (
<View style={styles.container}>
.....
......
</View>
);
}
}
export default connect(mapStateToProps, {callCancel, setBookingstatus})(BookingCard);
// export {BookingCard};
BookingPage( Component including Listview )
import React from 'react';
import {ListView, View} from 'react-native';
import { connect } from 'react-redux';
import {Spinner} from './common';
import {BookingCard} from './BookingCard';
import {fetchBooking} from '../actions';
class BookingPage extends React.Component {
componentWillMount() {
this.props.fetchBooking();
}
ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
renderRow(booking) {
return <BookingCard booking={booking} />;
}
renderButton() {
if (this.props.loading) {
return <Spinner size="large" />;
}
return (
<ListView
dataSource={this.ds.cloneWithRows(this.props.bookings)}
enableEmptySections
renderRow={this.renderRow}
/>
);
}
render() {
console.log('onRender BookingPage');
return (
<View>
{this.renderButton()}
</View>
);
}
}
const mapStateToProps = ({ booking }) => {
const { bookings, loading } = booking;
return { bookings, loading };
};
export default connect(mapStateToProps, {fetchBooking})(BookingPage);
Since you're exporting your component default like this:
export default connect(mapStateToProps, {callCancel, setBookingstatus})(BookingCard);
The line below fails because it expects a named export.
import {BookingCard} from './BookingCard';
You should either fix your import like this:
import BookingCard from './BookingCard';
or export it like
export const MyConnectedComponent = connect(mapStateToProps, {callCancel, setBookingstatus})(BookingCard);
You can find out more at MDN's website.

Categories