Reputation: 305
I'm trying to upgrade a legacy React Native app (that also uses Redux) to the latest version and I'm following these guidelines:
This is a sample of the old code base:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { compose } from 'redux'
import { View, Text } from 'react-native'
import { Colors } from '../../Themes'
import FontAwesome from 'react-native-vector-icons/FontAwesome'
import Octicons from 'react-native-vector-icons/Octicons'
import Feather from 'react-native-vector-icons/Feather'
import AntDesign from 'react-native-vector-icons/AntDesign'
import StatusLabel from '../WcGlobals/StatusLabel'
import OrderItemsList from '../WcGlobals/OrderItemsList'
import CurrencySymbols from '../../Constants/CurrencySymbols'
import FullScreenLoader from '../FullScreenLoader'
import { CapabilitiesSelectors } from '../../Redux/CapabilitiesRedux'
import moment from 'moment'
import Menu, {
MenuTrigger,
MenuOptions,
MenuOption,
renderers
} from 'react-native-popup-menu'
import styles from './Styles/OrderListItemStyle'
const { SlideInMenu } = renderers
class OrderListItem extends Component {
// // Prop type warnings
static propTypes = {
order: PropTypes.object,
index: PropTypes.number,
capabilities: PropTypes.object
}
statuses = [
{ label: 'On Hold', value: 'on-hold' },
{ label: 'Processing', value: 'processing' },
{ label: 'Completed', value: 'completed' },
{ label: 'Pending', value: 'pending' }
]
getOrderStatus = () => {
const { order } = this.props
return this.statuses.filter(
({ value }) => {
if (order.status === 'processing') { return value === 'completed' }
if (order.status === 'completed') { return false }
if (order.status === 'on-hold') { return value === 'completed' || value === 'processing' }
if (order.status === 'pending') { return value !== order.status }
}
)
}
onSelect = (value) => {
const { onUpdate, order } = this.props
onUpdate(order.id, value)
}
render () {
if (this.props.updating) {
return (<FullScreenLoader />)
}
const statuses = this.getOrderStatus()
// console.log(statuses);
const { order, index } = this.props
const date = moment(order.date_created).format('DDMMM YYYY')
const time = moment(order.date_created).format('hh:mmA')
if (!this.props.capabilities.order_status_update && statuses.length !== 0) {
return (
<Menu name={`order-status-${this.props.index}`} renderer={SlideInMenu} style={this.props.index ? styles.listItemContainer : styles.listItemContainerFirst} onSelect={this.onSelect}>
<MenuTrigger>
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} />
<OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}> Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</MenuTrigger>
<MenuOptions customStyles={{ optionText: styles.slideInOption }}>
<MenuOption key={'00'} value={''} disabled disableTouchable text={'Tap any one of the options below to change the order status'} />
{statuses.map(({ label, value }) => (<MenuOption key={value} value={value} text={label} />))}
</MenuOptions>
</Menu>
)
} else {
return (
<View style={this.props.index ? styles.listItemContainer : styles.listItemContainerFirst} >
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} /><OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}>Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</View>
)
}
}
}
const mapStateToProps = (state) => {
return {
capabilities: CapabilitiesSelectors.getData(state)
}
}
export default compose(
connect(mapStateToProps)
)(OrderListItem)
I'm trying to follow this guide: https://react-native-community.github.io/upgrade-helper/?from=0.59.5&to=0.63.2 and this is what I have come up with so far:
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { compose } from 'redux'
import {Platform, StyleSheet, Text, View} from 'react-native';
import { Colors } from '../../Themes'
import FontAwesome from 'react-native-vector-icons/FontAwesome'
import Octicons from 'react-native-vector-icons/Octicons'
import Feather from 'react-native-vector-icons/Feather'
import AntDesign from 'react-native-vector-icons/AntDesign'
import StatusLabel from '../WcGlobals/StatusLabel'
import OrderItemsList from '../WcGlobals/OrderItemsList'
import CurrencySymbols from '../../Constants/CurrencySymbols'
import FullScreenLoader from '../FullScreenLoader'
import { CapabilitiesSelectors } from '../../Redux/CapabilitiesRedux'
import moment from 'moment'
import Menu, {
MenuTrigger,
MenuOptions,
MenuOption,
renderers
} from 'react-native-popup-menu'
import styles from './Styles/OrderListItemStyle'
const { SlideInMenu } = renderers
const OrderListItem = ({order,index,capabilities}) => {
//class OrderListItem extends Component {
// // Prop type warnings
OrderListItem.propTypes = {
order: PropTypes.object,
index: PropTypes.number,
capabilities: PropTypes.object
}
statuses = [
{ label: 'On Hold', value: 'on-hold' },
{ label: 'Processing', value: 'processing' },
{ label: 'Completed', value: 'completed' },
{ label: 'Pending', value: 'pending' }
]
getOrderStatus = () => {
const { order } = this.props
return this.statuses.filter(
({ value }) => {
if (order.status === 'processing') { return value === 'completed' }
if (order.status === 'completed') { return false }
if (order.status === 'on-hold') { return value === 'completed' || value === 'processing' }
if (order.status === 'pending') { return value !== order.status }
}
)
}
onSelect = (value) => {
const { onUpdate, order } = this.props
onUpdate(order.id, value)
}
render () {
if (this.props.updating) {
return (<FullScreenLoader />)
}
const statuses = this.getOrderStatus()
// console.log(statuses);
const { order, index } = this.props
const date = moment(order.date_created).format('DDMMM YYYY')
const time = moment(order.date_created).format('hh:mmA')
if (!this.props.capabilities.order_status_update && statuses.length !== 0) {
return (
<Menu name={`order-status-${this.props.index}`} renderer={SlideInMenu} style={this.props.index ? styles.listItemContainer : styles.listItemContainerFirst} onSelect={this.onSelect}>
<MenuTrigger>
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} />
<OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}> Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</MenuTrigger>
<MenuOptions customStyles={{ optionText: styles.slideInOption }}>
<MenuOption key={'00'} value={''} disabled disableTouchable text={'Tap any one of the options below to change the order status'} />
{statuses.map(({ label, value }) => (<MenuOption key={value} value={value} text={label} />))}
</MenuOptions>
</Menu>
)
} else {
return (
<View style={this.props.index ? styles.listItemContainer : styles.listItemContainerFirst} >
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} /><OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}>Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</View>
)
}
}
}
const mapStateToProps = (state) => {
return {
capabilities: CapabilitiesSelectors.getData(state)
}
}
export default compose(
connect(mapStateToProps)
)(OrderListItem)
Now I'm getting the following error when I run my app:
ERROR [Error: TransformError SyntaxError: /App/Components/OrderListing/OrderListItem.js: Unexpected token, expected ";" (61:12)
59 | }
60 |
> 61 | render () {
| ^
62 | if (this.props.updating) {
63 | return (<FullScreenLoader />)
64 | }]
Any idea how I can resolve this?
Upvotes: 0
Views: 203
Reputation: 130132
Class components still exists in current version of React and there is no reason to replace them completely with functional components. However, if you want to do it, you have to realize that the component is the render
function. You cannot have attributes and methods inside a functional component. It's a function, therefore you will need variables and statements.
Also, you should not use this
at all.
The basic form is:
const OrderListItem = props => {
return ...
};
OrderListItem.propTypes = { ... };
In full, it should be similar to the following (not tested).
const OrderListItem = props => {
const statuses = [
{ label: 'On Hold', value: 'on-hold' },
{ label: 'Processing', value: 'processing' },
{ label: 'Completed', value: 'completed' },
{ label: 'Pending', value: 'pending' }
];
const getOrderStatus = () => {
const { order } = props
return statuses.filter(
({ value }) => {
if (order.status === 'processing') { return value === 'completed' }
if (order.status === 'completed') { return false }
if (order.status === 'on-hold') { return value === 'completed' || value === 'processing' }
if (order.status === 'pending') { return value !== order.status }
}
)
};
const onSelect = (value) => {
const { onUpdate, order } = props;
onUpdate(order.id, value)
};
if (props.updating) {
return (<FullScreenLoader />)
}
const statuses = getOrderStatus()
// console.log(statuses);
const { order, index } = props
const date = moment(order.date_created).format('DDMMM YYYY')
const time = moment(order.date_created).format('hh:mmA')
if (!props.capabilities.order_status_update && statuses.length !== 0) {
return (
<Menu name={`order-status-${props.index}`} renderer={SlideInMenu} style={props.index ? styles.listItemContainer : styles.listItemContainerFirst} onSelect={onSelect}>
<MenuTrigger>
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} />
<OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}> Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</MenuTrigger>
<MenuOptions customStyles={{ optionText: styles.slideInOption }}>
<MenuOption key={'00'} value={''} disabled disableTouchable text={'Tap any one of the options below to change the order status'} />
{statuses.map(({ label, value }) => (<MenuOption key={value} value={value} text={label} />))}
</MenuOptions>
</Menu>
)
} else {
return (
<View style={props.index ? styles.listItemContainer : styles.listItemContainerFirst} >
<View style={styles.listItemRow}>
<View style={styles.orderNameStatusContainer}>
<View style={styles.orderNoCustContainer}>
<Text style={styles.orderName}>{'#' + order.id}</Text>
{ (order.customer_id)
? (<Text style={styles.orderCustomer}>{' (By ' + order.billing.first_name + ' ' + order.billing.last_name + ')' }</Text>)
: (<Text style={styles.orderCustomer}>{' (By Guest)' }</Text>)
}
</View>
<View style={styles.orderStatusItemsContainer}>
<StatusLabel status={order.status} />
</View>
</View>
<View style={styles.orderProductContainer}>
<Octicons size={17} name={'package'} color={Colors.secondaryColor} /><OrderItemsList items={order.line_items} />
</View>
<View style={[styles.orderDateContainer]}>
<AntDesign size={16.5} name={'clockcircleo'} color={Colors.secondaryColor} /><Text style={styles.orderDate}>{ date + ' | ' + time }</Text>
<View style={styles.orderCommissionContainer}>
<FontAwesome size={17} name={'money'} color={Colors.secondaryColor} /><Text style={styles.orderCommission}>Earnings: {CurrencySymbols[order.currency]}{Math.round(order.vendor_order_details.total_commission * 100) / 100 }</Text>
</View>
</View>
</View>
</View>
)
}
}
OrderListItem.propTypes = {
order: PropTypes.object,
index: PropTypes.number,
capabilities: PropTypes.object
};
const mapStateToProps = (state) => {
return {
capabilities: CapabilitiesSelectors.getData(state)
}
}
export default compose(
connect(mapStateToProps)
)(OrderListItem)
Of course, now some of your former methods are pointless, for example getOrderStatus
can be just:
const statuses = (() => {
const { order } = this.props
return statuses.filter(
({ value }) => {
if (order.status === 'processing') { return value === 'completed' }
if (order.status === 'completed') { return false }
if (order.status === 'on-hold') { return value === 'completed' || value === 'processing' }
if (order.status === 'pending') { return value !== order.status }
}
)
})();
(note this is just an anonymous closure, that is called immediately. And in general, it would work better as a switch-case
over order.status
).
You can also move helper methods completely out of the functional parameters, not passing them props
but only the necessary parameters. That will make them easier to debug and maintain.
Upvotes: 1