react app, load components based on dropdown option - javascript

Currently, in my react app, I have a parent component which is housing two child components (TrendsComonent and BaselineComponent) and they load successfully. The parent component also has a dropdown component loaded.
What i want to do is set a default Component to load in the parent initially, but I want to map each child component to the dropdown options.
For instance, when the parent component is visited I would like to have TrendsComponent load initially as the default but have it tied to the trends dropdown option, as well as have the BaselineComponent mapped to the baseline option of the dropdown.
Basically, I just want to load components based on the dropdown option as opposed to all at once
TrendComponent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
const styles = StyleSheet.create({
TrendsComponent: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
textAlign: 'center'
},
TrendsTitle: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems:'center'
}
});
class TrendsComponent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div className={css(styles.TrendsComponent)}>
<div className={css(styles.TrendsComponent)}>
<div className="mixed-chart">
<Chart
/>
</div>
</div>
</div>
</div>
);
}
}
export default TrendsComponent;
BaselineComponent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
const styles = StyleSheet.create({
TrendsComponent: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
textAlign: 'center'
},
TrendsTitle: {
display: 'flex',
flexDirection: 'row',
justifyContent: 'center',
alignItems:'center'
}
});
class BaselineComponent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div >
<div >
<div className="mixed-chart">
<Chart
/>
</div>
</div>
</div>
</div>
);
}
}
export default BaselineComponent;
Then I have the parent component that currently holds that component as well as the dropdown
trendparent.js
import React, { Component } from "react";
import Chart from "react-apexcharts";
import { StyleSheet, css } from 'aphrodite/no-important';
import TrendsComponent from './Trendscomponent';
import BaselineComponent from './BaselineComponent';
import TrendDropdownComponent from './TrendDropdownComponent';
class trendparent extends Component {
render() {
return (
<div>
<div className={css(styles.TrendsTitle)}>
Net Calories
</div>
<div>
<div>
<div>
<TrendsComponent />
<BaselineComponent />
</div>
</div>
</div>
<div style={{height:50}}>
</div>
<div>
<TrendDropdownComponent />
</div>
</div>
);
}
}
export default trendparent;
dropdown.js
import React, { Component } from "react";
import { makeStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormHelperText from '#material-ui/core/FormHelperText';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 220,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function SimpleSelect() {
const classes = useStyles();
const [age, setAge] = React.useState('');
const inputLabel = React.useRef(null);
const handleChange = event => {
setAge(event.target.value);
};
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Calories</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
onChange={handleChange}
>
<MenuItem value={10}>Trend</MenuItem>
<MenuItem value={20}>Baseline</MenuItem>
</Select>
</FormControl>
</div>
);
}

The question here is what you really mean by "load".
1) If what you mean by "load" means actually to only render a component that was statically imported (already declared in the beginning of the file), then all you have to do is set some default value on the state i.e. :
state = {
renderComponentX: false
}
And then on the dropdown change method change the state to true:
setState({"renderComponentX":true})
And inside render have a condition as :
{this.state.renderComponentX && <ComponentX />}
2) If on the other hand what you want is really to dynamically load components then it's a bit more complicated :
You need to create a component that Asynchronously loads other components.
I normally create an array of randomKeys on the state of the component, at the constructor:
constructor(props) {
super(props);
// Dynamic Key Generation for dynamic view loading
let randomKeys = [];
while(randomKeys.length < 10){
let y = Math.random()*10000;
if(randomKeys.indexOf(y) === -1) randomKeys.push(y);
}
this.state = {
randomKeys
};
}
So that each of the new imported components will have a different Key.
In this case it's hardcoded to 0 but if you want to make this inside an iterator, you would have to create a variable to act as a counter to keep updating the index such as randomKeys[i] where i needs to grow from 0 to the length of components you want to import. Also you need to make sure to generate enough keys in the constructor; this one is only generating 10, because this was for manual import, not within an iterator.
<AsyncComponent key={this.state.randomKeys[0]} getComponent={() => import('../Login/Login.js')} />
and my AsyncComponent looks like this :
import React from 'react';
import PropTypes from 'prop-types';
export default class AsyncComponent extends React.Component {
state = {
AsyncModule: null,
};
componentDidMount() {
let that = this;
this.unmounted = false;
this.props.getComponent()
.then(module => {
console.log("AsyncComponent loaded module:",module);
return module.default;
})
.then(AsyncModule => {
if(that.unmounted!==true) {
that.setState({AsyncModule})
}
});
}
componentDidUpdate() {
}
componentWillUnmount() {
this.unmounted = true;
}
render() {
const {loader, ...childProps} = this.props;
const {AsyncModule} = this.state;
if(AsyncModule) {
return (<AsyncModule {...childProps} />)
}
if(loader) {
console.log('loader = ',loader);
return <div>Loading...</div>;
}
return null;
}
}
AsyncComponent.propTypes = {
getComponent: PropTypes.func,
loader: PropTypes.element
};

Related

React360-Redux:Communication between 2 roots components via redux

I have 2 root components in react360.I have the main panel with information and my products and i have my 3d model.I want to communicate one another.Μore specifically I just want to click on the product then the color from my 3d model changes.At this time, my 3d model has value from the store I have originally defined, but while the price is changing, it is not renewed in the 3d model.for example when the application starts the original color of my model is blue but when I click on the first item it does not change to red. Wrere is the problem?????before
after
client.js
import { ReactInstance } from "react-360-web";
import { Location } from "react-360-web";
function init(bundle, parent, options = {}) {
const r360 = new ReactInstance(bundle, parent, {
// Add custom options here
fullScreen: true,
...options
});
// Render your app content to the default cylinder surface
r360.renderToSurface(
r360.createRoot("Center", {
/* initial props */
}),
r360.getDefaultSurface()
);
r360.renderToLocation(
r360.createRoot("React3DView"),
r360.getDefaultLocation()
);
// Load the initial environment
r360.compositor.setBackground(r360.getAssetURL("360_world.jpg"));
}
window.React360 = { init };
index.js
import { AppRegistry } from "react-360";
import Center from "./components/center";
import React3DView from "./components/obj";
AppRegistry.registerComponent("Center", () => Center);
AppRegistry.registerComponent("React3DView", () => React3DView);
reducer
initialState = {
data: [
{ id: 1, value: "MILEPTY.png" },
{ id: 2, value: "cleveland.png" },
{ id: 3, value: "phila.png" },
{ id: 4, value: "raptors.png" },
{ id: 5, value: "rockets.png" }
],
currentinfo: "Hello.Press click on T-shirt to show information",
currentcolor: "blue"
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case "INFO":
if (action.key === 1) {
return {
...state,
currentinfo: "Milwaukee bucks",
currentcolor: "red"
};
}
if (action.key === 2) {
return {
...state,
currentinfo: "Cleveland Cavaliers",
currentcolor: "green"
};
}
if (action.key === 3) {
return { ...state, currentinfo: "Philadelphia 76xers" };
}
if (action.key === 4) {
return { ...state, currentinfo: "Toronto Raptors" };
}
if (action.key === 5) {
return { ...state, currentinfo: "Huston Rockets" };
}
default:
return state;
}
};
export default reducer;
centerPanel
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import Products from "./products";
import { connect } from "react-redux";
class CenterPanel extends React.Component {
render() {
return (
<View style={styles.panel}>
<View style={{ flex: 1, flexDirection: "row" }}>
<View
style={{
width: 250,
height: 600
}}
>
<Text style={{ marginTop: "100" }}>{this.props.currentinfo}</Text>
</View>
<View
style={{
width: 1000,
height: 600,
backgroundColor: "green"
}}
>
<View style={{ flex: 1, flexDirection: "row" }}>
{this.props.data.map(element => (
<Products
key={element.id}
value={element.value}
id={element.id}
/>
))}
</View>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
panel: {
// Fill the entire surface
width: 1000,
height: 600,
backgroundColor: "rgba(255, 255, 255, 0.4)"
}
});
const mapStateToProps = state => {
return {
data: state.data,
currentinfo: state.currentinfo
};
};
export default connect(mapStateToProps)(CenterPanel);
products
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { connect } from "react-redux";
class Products extends React.Component {
state = {
img: this.props.value
};
render() {
return (
<View
style={styles.panelimages}
onInput={() => this.props.onText(this.props.id)}
>
<Image style={styles.images} source={asset(this.state.img)} />
</View>
);
}
}
const styles = StyleSheet.create({
panelimages: {
width: 150,
height: 150,
marginTop: 200,
backgroundColor: "white"
},
images: {
width: 150,
height: 150
}
});
const mapDispatchToProps = dispatch => {
return {
onText: id => dispatch({ type: "INFO", key: id })
};
};
export default connect(
null,
mapDispatchToProps
)(Products);
center
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import CenterPanel from "./centerPanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class Center extends React.Component {
render() {
return (
<Provider store={store}>
<CenterPanel />
</Provider>
);
}
}
objpanel
import React from "react";
import {
asset,
AppRegistry,
StyleSheet,
Text,
View,
VrButton,
Image
} from "react-360";
import Entity from "Entity";
import { connect } from "react-redux";
class Object3d extends React.Component {
render() {
return (
<View>
<Entity
source={{ obj: asset("t-shirt.obj") }}
style={{
transform: [{ translate: [-3.5, -3.5, -2.8] }],
color: this.props.currentcolor -------->here is problem
}}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
currentcolor: state.currentcolor
};
};
export default connect(mapStateToProps)(Object3d);
obj
import React from "react";
import { AppRegistry, StyleSheet, Text, View, Image, asset } from "react-360";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "../store/reducer";
import Object3d from "./objpanel";
// const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
const store = createStore(reducer);
export default class React3DView extends React.Component {
render() {
return (
<Provider store={store}>
<Object3d />
</Provider>
);
}
}
I've tried to do this with redux but in the end I had more problems implementing it than it was worth. In order to implement something like that you would need to follow the code that is described here:
React 360 multi panel example
Additionally, I've implemented what you are trying to do without redux. You can look at the code in this repository and also view the production link here. Its modeled after the react 360 code.
CryptoDashboardVR repo
CryptodashboardVR Multipanel synchronization
Finally, If you still need help, check out my course on React 360. I explain the concepts used. Udemy react 360.
Hope that helps. For now, I would abandon the redux approach until maybe 2.0 comes out.

Custom input component in react native input is not working as expected

I am trying to make a custom input component with onChangeText but whenever I start typing in the textInput box I get an error. I have checked the code many times and everything looks fine to me.
import React from "react";
import { TextInput, StyleSheet } from "react-native";
const defaultInput = props => (
<TextInput
underlineColorAndroid="transparent"
{...props}
style={[styles.input, props.style]}
/>
)
const styles = StyleSheet.create({
input: {
width: "100%",
borderWidth: 1,
borderColor: "#eee",
padding: 5,
marginTop: 8,
marginBottom: 8
}
});
export default defaultInput;
This is my sub component where I am using my custom component.
import React, { Component } from "react";
import { View, TextInput, Button, StyleSheet } from "react-native";
import DefaultInput from "../UI/DefaultInput/DefaultInput";
const placeInput = props =>(
<DefaultInput
placeholder="Place Name"
value={props.placeName}
onChangeText={props.onChangeText}
/>
)
export default placeInput;
This is the screen where I am using my sub component.
import React, { Component } from 'react'
import { Text, View, TextInput, Button, StyleSheet, ScrollView, Image } from 'react-native'
import { connect } from 'react-redux'
import placeImage from '../../asset/pic.jpg'
import PlaceInput from '../../component/PlaceInput/PlaceInput'
import { addPlace } from '../../store/actions/index'
import { Navigation } from 'react-native-navigation'
// import DefaultInput from '../../component/UI/DefaultInput/DefaultInput'
import HeadingText from '../../component/UI/HeadingText/HeadingText'
import MainText from '../../component/UI/MainText/MainText'
import PickImage from '../../component/PickImage/PickImage'
import PickLocation from '../../component/PickLocation/PickLocation'
class SharePlace extends Component {
state={
placeName:""
}
constructor(props) {
super(props);
this.props.navigator.setOnNavigatorEvent(this.OnNavigatorEvent);
}
placeNameChangedHandler = val => {
this.setState({
placeName: val
});
};
OnNavigatorEvent = (event) => {
console.log(event);
if (event.type === "NavBarButtonPress") {
if (event.id === "sideDrawerToggle") {
this.props.navigator.toggleDrawer({
side: "left"
})
}
}
}
placeAddedHandler = () => {
if(this.state.placeName.trim() !== "")
{
this.props.onAddPlace(this.state.placeName);
}
}
render() {
return (
// <ScrollView contentContainerStyle={styles.conatiner}>
<ScrollView>
<View style={styles.conatiner}>
<MainText>
<HeadingText>Share a place with us!</HeadingText>
</MainText>
<PickImage />
<PickLocation />
<PlaceInput
placeName={this.state.placeName}
onChangeText={this.placeNameChangedHandler}
/>
<View style={styles.button}>
<Button title="share the place" onPress={this.placeAddedHandler} />
</View>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
conatiner: {
flex: 1,
alignItems: "center"
},
placeholder: {
borderWidth: 1,
borderColor: "black",
backgroundColor: "#eee",
width: "80%",
height: 150
},
button: {
margin: 8
},
imagePreview: {
width: "100%",
height: "100%"
}
})
const mapDispatchToProps = dispatch => {
return {
onAddPlace: (placeName) => dispatch(addPlace(placeName))
}
}
export default connect(null, mapDispatchToProps)(SharePlace)
This is the error I am getting.
ExceptionsManager.js:63 Invariant Violation: TextInput(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
This error is located at:
in TextInput (at DefaultInput.js:5)
in defaultInput (at PlaceInput.js:7)
in placeInput (at SharePlace.js:60)
in RCTView (at View.js:60)
in View (at SharePlace.js:54)
in RCTScrollContentView (at ScrollView.js:791)
in RCTScrollView (at ScrollView.js:887)
in ScrollView (at SharePlace.js:53)
in SharePlace (created by Connect(SharePlace))
in Connect(SharePlace) (at Navigation.js:83)
in Provider (at Navigation.js:82)
in _class2 (at renderApplication.js:33)
in RCTView (at View.js:60)
in View (at AppContainer.js:102)
in RCTView (at View.js:60)
in View (at AppContainer.js:122)
in AppContainer (at renderApplication.js:32)
Using typescript,
import {TextInput, TextInputProps, View} from "react-native";
declare a props interface:
interface Props extends TextInputProps {}
// This ensures that all the properties associated with react-native's
// TextInput component, are associated with your custom-input component as well.
decalare your custom-input component:
const CustomInput = (props: Props) => {
<TextInput onChangeText={props.onChangeText} placeholder={props.placeholder} style={[props.style]} />
}
export default CustomInput;
use your custom-input component in LoginScreen.tsx say;
import React from "react";
import CustomInput from "../CustomInput";
const LoginScreen = () => {
const handleChange = (value: string) =>{
....
}
return(
<CustomInput placeholder="email" onChangeText={value => handleChange(value) />
)
your code working fine as the way I ran it, maybe you have problem to import PlaceInput or DefaultInput:
import React, { Component } from 'react';
import { View, Text, FlatList, ScrollView,TextInput, Image,StyleSheet } from 'react-native';
export default class Test extends Component {
constructor(props) {
super(props);
this.state = {
placeName: ""
}
}
placeNameChangedHandler = val => {
this.setState({
placeName: val
});
};
render() {
return (
<View>
<PlaceInput
placeName={this.state.placeName}
onChangeText={this.placeNameChangedHandler}
/>
</View>
);
}
}
const PlaceInput = props => (
<DefaultInput
placeholder="Place Name"
value={props.placeName}
onChangeText={props.onChangeText}
/>
)
const DefaultInput = props => (
<TextInput
underlineColorAndroid="transparent"
{...props}
style={[styles.input, props.style]}
/>
)
const styles = StyleSheet.create({
input: {
width: "100%",
borderWidth: 1,
borderColor: "#eee",
padding: 5,
marginTop: 8,
marginBottom: 8
}
});

React HOC - Generic Container

Wizard and WizardPage
I am trying to build a generic Wizard and WizardPages to be generic a reusable across my app. I think the Wizard component as the one in charge of managing the state, and the WizardPage that is going to work as a wrapper, and will render Back, Cancel and Next buttons. It's suppose that the Next button (maybe the Back too) should dispatch an redux action. This action, could be different depending on the component being wrapped. This is what i have (not complete version):
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import withWizardLayout from '../../hoc/WithWizardLayout';
class Wizard extends Component {
constructor(props) {
super(props);
this.state = {
page: 0,
};
}
nextPage = () => {
this.setState({ page: this.state.page + 1 });
};
previousPage = () => {
this.setState({ page: this.state.page - 1 });
};
render() {
const { wizardPages } = this.props;
const { page } = this.state;
const wizardItem = wizardPages[page];
const nextPage = this.nextPage;
const previousPage = this.previousPage;
const ComponentWrapped = withWizardLayout(wizardItem.ComponentWrapped, nextPage, previousPage);
return (
<ComponentWrapped />
);
}
}
export default Wizard;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { compose } from 'react-apollo';
import { connect } from 'react-redux';
import { Flex, Box } from 'reflexbox';
import { BlueRoundButton, GreyRoundButton } from '../components/Button';
export default function withWizardLayout(ComponentDependent, nextPageCallBack, previousPageCallback) {
class WizardPage extends Component {
previousPage = () => {
};
nextPage = () => {
this.props.test();
};
render() {
const { ComponentWrapped, isFirstPage, isLastPage } = ComponentDependent;
return (
<Flex column>
<ComponentWrapped
isLastPage={isLastPage}
isFirstPage={isFirstPage}
>
<Flex justify='flex-end'>
<Flex mr='auto' w={0.1}>
<GreyRoundButton style={{ fontWeight: '500', position: 'relative', top: '10%' }}>Back</GreyRoundButton>
</Flex>
<Flex w={0.08} mr={2} align='center' justify='center' style={{ textAlign: 'center' }}>
<span>Cancel</span>
</Flex>
<Flex w={0.15} justify='center'>
<BlueRoundButton onClick={this.nextPage} style={{ position: 'relative', top: '10%', fontWeight: '500' }}>Continue</BlueRoundButton>
</Flex>
</Flex>
</ComponentWrapped>
</Flex>
);
}
}
CustomersContainer
import { compose } from 'react-apollo';
import { connect } from 'react-redux';
import CustomerImport from '../components/Settings/CustomerImport';
import { withWizardLayout } from '../hoc/WithWizardLayout';
const mapStateToProps = null;
const mapDispatchToProps = dispatch => (
{
test: () => (dispatch(console.log("hi"))),
}
);
export default compose(connect(null, mapDispatchToProps))(CustomerImport);
Connected Component
import React, { Component } from 'react';
import styled from 'styled-components';
import {
SettingBlock,
NotifyBlock,
SuccessMessage,
ErrorMessage,
Instructions,
} from './styles';
import ExcelUploader from '../ExcelUploader';
const ProgressBar = styled.div`
width: 0;
height: 30px;
background-color: Green;
`;
const ExcelWrapper = styled.div`
margin-bottom: 4rem;
`;
export default class CustomerImport extends Component {
constructor(props) {
super(props);
this.state = {
progress: 0,
notify: {
success: {
message: '',
active: false,
},
error: {
message: '',
active: false,
},
},
};
}
render() {
const { success, error } = this.state.notify;
const ButtonsWrapper = this.props.children;
return (
<div>
<NotifyBlock>
<SuccessMessage className={success.active ? 'active' : null}>{success.message}</SuccessMessage>
<ErrorMessage className={error.active ? 'active' : null}>{error.message}</ErrorMessage>
</NotifyBlock>
<SettingBlock>
<h3>
Import your customers
</h3>
<ProgressBar style={{ width: `${this.state.progress}%` }} />
<Instructions>
Select an Excel file containing your customer information.
Need a template? Grab one here.
</Instructions>
<ExcelWrapper>
<ExcelUploader />
</ExcelWrapper>
{ButtonsWrapper}
</SettingBlock>
</div>
);
}
}
This is how i am supposed to render the Generic Wizard, we can have X wizardPages:
const wizardPages = [
{
ComponentWrapped: CustomersContainer,
isFirstPage: false,
isLastPage: false,
},
];
<Wizard wizardPages={wizardPages} />
The problem with this approach, is that i want on the onClick of the buttons in withWizardLayout:
1) Execute the callback on the Father (that's possible, i am passing as prop the handler)
2) Call the dispatch action received of the container. (i am not able not access the dispatched action, in this case, this.props.test)
How can i refactor this, to think a generic way to handle this? I think another ways to refactor this (having different withWizardLayout functions, but i am having render problems on the console).
Maybe i didn't architect this in the best way.
Help!

React Native Element type is invalid expected a string but got undefined

I'm following a course on react-native and I just ran into this error when trying to add a modal component to a page:
Element type is invalid: expected a string(for built-in components) or a class/function (for composite components) but got: undefined.
Here's my code:
EmployeeEdit.js
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Communications from 'react-native-communications';
import { employeeUpdate, employeeSave, employeeReset } from '../actions';
import { Card, CardSection, Button, Confirm } from './common';
import EmployeeForm from './EmployeeForm';
class EmployeeEdit extends Component {
constructor(props) {
super(props);
this.state = { showModal : false};
this.onButtonPress = this.onButtonPress.bind(this);
this.onTextPress = this.onTextPress.bind(this);
}
componentWillMount() {
_.each(this.props.employee, (value, prop) => {
this.props.employeeUpdate({prop, value});
});
}
componentWillUnmount() {
this.props.employeeReset();
}
onButtonPress(){
const { name, phone, shift } = this.props;
this.props.employeeSave({ name, phone, shift, uid: this.props.employee.uid });
}
onTextPress(){
const { name, phone, shift } = this.props;
Communications.text(phone, `Hello ${name}, your upcoming shift is on ${shift}`);
}
render () {
return (
<Card>
<EmployeeForm {...this.props} />
<CardSection>
<Button onPress={this.onButtonPress}>
Save Changes
</Button>
</CardSection>
<CardSection>
<Button onPress={this.onTextPress}>
Text Schedule
</Button>
</CardSection>
<CardSection>
<Button onPress={()=> this.setState({ showModal: !this.state.showModal })}>
Fire Employee
</Button>
</CardSection>
<Confirm
visible={this.state.showModal}
>
Are you sure you want to fire this employe?
</Confirm>
</Card>
);
}
}
const mapStateToProps = (state) => {
const {name, phone, shift} = state.employeeForm;
return {name, phone, shift};
};
export default connect(mapStateToProps, {
employeeUpdate,
employeeSave,
employeeReset
})(EmployeeEdit);
Confirm.js
import React from 'react';
import { Text, View, Modal } from 'react-native';
import { CardSection } from './CardSection';
import { Button } from './Button';
const Confirm = ({ children, visible, onAccept, onDecline }) => {
const { containerStyle, textStyle, cardSectionStyle } = styles;
return (
<Modal
visible={visible}
transparent
animationType='slide'
onRequestClose={() => {}}
>
<View style={containerStyle}>
<CardSection style={cardSectionStyle}>
<Text style={textStyle}>
{children}
</Text>
</CardSection>
<CardSection>
<Button onPress={onAccept}>Yes</Button>
<Button onPress={onDecline}>No</Button>
</CardSection>
</View>
</Modal>
);
};
const styles = {
cardSectionStyle: {
justifyContent: 'center'
},
textStyle: {
flex: 1,
fontSize: 18,
textAlign: 'center',
lineHeight: 40
},
containerStyle: {
backgroundColor: 'rgba(0, 0, 0, 0.75)',
position: 'relative',
flex: 1,
justifyContent: 'center'
}
};
export default { Confirm };
The error only occurs when I add the confirm component to EmployeeEdit. When I remove the confirm component at the bottom the error goes away. Is there some error in my confirm component?
Thanks
at the bottom of Confirm.js it should be
export { Confirm };
not
export default { Confirm };
When you're importing Confirm using curly braces
import { Card, CardSection, Button, Confirm } from './common';
make sure you're not exporting it using default like what you did:
export default { Confirm };
because once you use
default syntax, it doesn't require curly braces syntax when importing.
You can avoid the flower braces in all.
Do this.
In your Confirm.js
export default Confirm
In your EmployeeEdit.js
import Confirm from './Confirm'
As you see, I have omitted the braces. According to the ES6 Documentation, if a module defines a default export, then you can import the default export without the use of curly braces. Refer here: What is "export default" in javascript?

render component based on state in react native

I am using react-native-side-menu for the menu in the app. Since this module using state to control the clicked menu, I would like to used it to render the component as well.
I am referred to this solution But it is not working, I got
Expected a component class, got [object Object].
This is what I did:
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
Image,
TouchableOpacity,
} from 'react-native';
import Menu from './menu';
import SideMenu from 'react-native-side-menu';
import First from './first';
import Second from './second';
module.exports = class Main extends Component {
state = {
isOpen: false,
selectedItem: 'First',
};
toggle() {
this.setState({
isOpen: !this.state.isOpen,
});
}
updateMenuState(isOpen) {
this.setState({ isOpen, });
}
onMenuItemSelected = (item) => {
this.setState({
isOpen: false,
selectedItem: item,
});
}
render() {
const menu = <Menu onItemSelected={this.onMenuItemSelected} />;
return (
<SideMenu
menu={menu}
isOpen={this.state.isOpen}
onChange={(isOpen) => this.updateMenuState(isOpen)}
>
<this.state.selectedItem />
<Button style={styles.button} onPress={() => this.toggle()}>
<Image
source={require('./assets/menu.png')} style={{width: 32, height: 32}} />
</Button>
</SideMenu>
);
}
}
....
UPDATE
Thanks for #NaderDabit suggest. Yes indeed, I should use
selectedItem: <First />,
instead.

Categories

Resources