I get an error that says this2.sampleFunction is not an object , I have tried adding a constructor and all from previous solutions.
export default class Play extends React.Component {
sampleFunction() {
console.log('Hello');
}
anotherFunction() {
return (
<Button
onPress={() => this.sampleFunction.bind(this)} />
);
}
render() {
<Deck
anotherFunction={this.anotherFunction()}
/>
}
}
EDIT : Here is the code in the deck component, it's just mainly a view tag
render() {
return (
<View>
{this.props.anotherFunction()}
</View>
);
}
Here is the image for the error :
I got the problem, It is same as I described in the comment. You are passing an element from Play to Deck but Deck expects a function. Please change render method of Play to
render() {
return (<Deck
anotherFunction={this.anotherFunction.bind(this)}
/>);
}
Related
I want to render a child element based on the state in its parent. I tried to do the following (simplified version of the code):
class DeviceInfo extends Component {
constructor(props) {
super(props);
this.state = {
currentTab: "General",
};
this.tabsMap = {
General:
<React.Fragment>
<GeneralCard
id={this.props.id}
/>
</React.Fragment>
}
navToggle(tab) {
this.setState({ currentTab: tab });
}
this.tabsMap = {
General:
<React.Fragment>
<GeneralCard
id={this.props.id}
/>
</React.Fragment>
};
render() {
return (
<React.Fragment>
<div className="container">
<Nav className="nav-tabs ">
<NavItem>
<NavLink
className={this.state.currentTab === "General" ? "active" : ""}
onClick={() => {
this.navToggle("General");
}}
>
General
</NavLink>
</div>
{ this.tabsMap[this.state.currentTab] }
</React.Fragment>
);
}
}
But it did not work properly. Only when I put the contents of the tabsMap straight in the render function body it works (i.e. as a react element rather then accessing it through the object). What am I missing here?
Instead of making tabsMap an attribute which is only set when the component is constructed, make a method that returns the object, and call it from render:
getTabsMap() {
return {
General:
<React.Fragment>
<GeneralCard
id={this.props.id}
/>
</React.Fragment>
}
};
render() {
...
{ this.getTabsMap()[this.state.currentTab] }
...
}
You defining instance property with this.tabsMap (should be syntax error):
export default class App extends React.Component {
tabsMap = { General: <div>Hello</div> };
// Syntax error
// this.tabsMap = { General: <div>World</div> };
render() {
// depends on props
const tabsMapObj = {
General: <div>Hello with some props {this.props.someProp}</div>
};
return (
<FlexBox>
{this.tabsMap['General']}
{tabsMapObj['General']}
</FlexBox>
);
}
}
Edit after providing code:
Fix the bug in the constructor (Note, don't use constructor, it's error-prone, use class variables).
Moreover, remember that constructor runs once before the component mount if you want your component to be synchronized when properties are changed, move it to render function (or make a function like proposed).
class DeviceInfo extends Component {
constructor(props) {
...
// this.props.id not defined in this point
this.tabsMap = {
General:
<React.Fragment>
<GeneralCard
id={props.id}
/>
</React.Fragment>
}
render() {
// make a function to change the id
this.tabsMap = {
General:
<React.Fragment>
<GeneralCard
id={this.props.id}
/>
</React.Fragment>
};
return (
<>
{ this.tabsMap[this.state.currentTab] }
</>
);
}
}
I think it's a this binding issue. Not sure if your tabsMap constant should have this in front of it.
Alternative answer... you can inline the expression directly in the render as
{ this.state.currentTab === 'General' && <GeneralCard id={this.props.id} /> }
I am still new to React Native and I struggle a bit with the programming paradigm. What I am trying to do (by following the structure of another React.js project) is to create a container (parent component) which contains a number of other components. My ultimate goal is to pass and handle all of the props in the parent component. Child component only shows them. My structure looks something like this:
export default class TemporaryCardRequestScreen extends React.Component {
constructor(props) {
super(props);
this.showDateTimePicker = this.showDateTimePicker.bind(this);
this.hideDateTimePicker = this.hideDateTimePicker.bind(this);
this.handleDatePicked = this.handleDatePicked.bind(this);
this.state.fromDateTime = {
isVisible: false,
value: new Date()
}
}
showDateTimePicker = () => { /*body*/ };
hideDateTimePicker = () => { /*body*/ };
handleDatePicked = date => { /*body*/ };
render() {
return (
<DateTimePickerComponent
isVisible={this.state.fromDateTime.isVisible}
onConfirmPressed={this.handleDatePicked}
onCancelPressed={this.hideDateTimePicker}
showDateTimePicker={this.showDateTimePicker}
value={this.state.fromDateTime.value}
/>
);
}
}
and the, my child component looks something like this:
// npm ref.: https://github.com/mmazzarolo/react-native-modal-datetime-picker
export default class DateTimePickerComponent extends Component {
constructor(props) {
super(props);
}
render() {
const {
isVisible,
onConfirmPressed,
onCancelPressed,
showDateTimePicker } = this.props;
return (
<>
<Button title="Show DatePicker" onPress={showDateTimePicker} />
<DateTimePicker
isVisible={isVisible}
onConfirm={onConfirmPressed}
onCancel={onCancelPressed}
mode='datetime'
is24Hour={false}
date={new Date()}
/>
</>
);
}
}
My focus now is on
onConfirmPressed={this.handleDatePicked}
currently, this.handleDatePicked accepts a single argument but I'd like it to accept one additional which is passed to it at the place being used in child component.
So, my ultimate goal would be to have something similar to this:
render() {
const {
isVisible,
onConfirmPressed,
onCancelPressed,
showDateTimePicker,
dateTimePickerId } = this.props;
return (
<>
<Button title="Show DatePicker" onPress={this.showDateTimePicker} />
<DateTimePicker
isVisible={isVisible}
onConfirm={onConfirmPressed(dateTimePickerId)}
onCancel={onCancelPressed}
mode='datetime'
is24Hour={false}
date={new Date()}
/>
</>
);
}
So, in this way, in my parent component I could have a single method which can handle the updates for a number of date time pickers in my container (This is actually my use-case). Instead of having the same type of handlers (with different property name) for pretty much the same thing.
UPDATE: Snack expo
You can capture 'onConfirm' of DateTimePickerComponent, then call parent function and pass in the dateTimePickerId.
TemporaryCardRequestScreen
// Modify to accept 2 arguments
handleDatePicked = (id, date) => {
if (id == "1") {
// code here
}
else if (id == "2") {
// code here
}
};
render() {
return (
<div>
<DateTimePickerComponent
isVisible={this.state.fromDateTime.isVisible}
onConfirmPressed={this.handleDatePicked}
onCancelPressed={this.hideDateTimePicker}
showDateTimePicker={this.showDateTimePicker}
value={this.state.fromDateTime.value}
dateTimePickerId="1"
/>
<DateTimePickerComponent
isVisible={this.state.fromDateTime.isVisible}
onConfirmPressed={this.handleDatePicked}
onCancelPressed={this.hideDateTimePicker}
showDateTimePicker={this.showDateTimePicker}
value={this.state.fromDateTime.value}
dateTimePickerId="2}
/>
</div>
);
}
DateTimePickerComponent
onMyCustomConfirmPressed = (date) => {
// Parent onConfirmPressed() shall accept 2 arguments
this.props.onConfirmPressed(this.props.dateTimePickerId, date)
}
render() {
const {
isVisible,
onConfirmPressed,
onCancelPressed,
showDateTimePicker,
dateTimePickerId } = this.props;
return (
<>
<Button title="Show DatePicker" onPress={this.showDateTimePicker} />
<DateTimePicker
isVisible={isVisible}
onConfirm={this.onMyCustomConfirmPressed}
onCancel={onCancelPressed}
mode='datetime'
is24Hour={false}
date={new Date()}
/>
</>
);
}
I am trying to create very simple multistep form using react. My main component which is handling state for steps looks like this:
...
renderStepItem = () => {
switch(this.state.step) {
case 1:
return <ImportStep nextStep={this.nextStep} />
case 2:
return <ImportStep previousStep={this.previousStep} nextStep={this.nextStep} />
case 3:
return <ImportStep previousStep={this.previousStep} />
}
}
...
This is switch which should return Component that should be rendered based on step state
Then render:
render() {
return(
{this.renderStepItem()}
)
}
The problem is that i am getting following error message:
Error
Objects are not valid as a React child (found: object with keys {nextStep}).
I was trying to go through some tuts etc to solve it. But i am guessing that i am passing something that i am unable to do.
Can anybody give me some hint please?
UPDATE:
render() {
const importSteps = AppConfig.importSteps;
return (
<Block extend={{
width: '80%',
margin: '25px auto'
}}>
<TabNav extend={{
border: '1px solid black',
}}
textAlign='center'>
{Object.keys(importSteps).map(function(key) {
return <TabNavItem >{importSteps[key].name} {importSteps[key].stepNo}</TabNavItem>;
}
)}
</TabNav>
<div>{ this.renderStepItem() }</div>
</Block>
)
}
}
UPDATE2: ImportItem component
import React, { Component } from 'react';
import { Block } from 'vcc-ui';
class ImportStep extends Component {
render() {
return (
<Block>
<h3>{this.props}</h3>
</Block>
)
}
}
export default ImportStep;
UPDATE
Use this.props.property in the render function. You can not use an object there in the ImportStep component.
Also, wrapping inside a <div> would be necessary when you have only one statement inside the return.
Wrap your this.renderStepItem() inside a <div></div>, and that should do.
Here is what your return statement should look like,
return (
<div>{ this.renderStepItem() }</div>
)
See this example: https://codesandbox.io/s/q35699jj49
I'm new in react-native and have some probems. In the fahterScreen I add some items to array and pass to childs as prop, I need that the child (CanastaScreen) update every 1seg and show the new value. I have the next code:
export default class CanastaScreen extends React.Component {
constructor(props) {
super(props);
setInterval( () => { this.render(); }, 1000);
};
render() {
return (
<Container>
<Content>
{this.props.screenProps.canasta.map( (item) => {
console.log(item.nombre);
return (
<Text>{item.nombre}</Text>
);
})}
</Content>
</Container>
);
}
}
Console output show correctly:
Item1
Item2
Item3
etc.
But the screen is always in blank. Some can help my about it ?
Thanks
First of all, you never should call render method of a component. in React Native, a component should update only if it's state changes. so if you have something like this :
<Parent>
<Canasta> ... </Canasta>
</Parent>
assuming that the changing variable is called foo in state of Parent, you need to pass it as prop to Canasta (child) and now by changing state of Parent (changing foo), Canasta should get updated. here's an example (calling updateFoo will update both Parent and Canasta):
class Parent extends Component {
constructor(props){
super(props); // it's recommended to include this in all constructors
this.state = { foo: initalValue } // give some value to foo
}
updateFoo(newValue){
this.setState({foo: newValue}) // setting state on a component will update it (as i said)
}
render() {
return(
<Canasta someProp={this.state.foo}> ... </Canasta>
)
}
}
}
After various changes, is found, the complete structure is: Parent(App.js) call children(Menu, Canasta). Menu allow add items to the shop-car and Canasta allow to sort and delete items. These are the important parts of the code:
App.js
export default class App extends React.Component {
constructor(props) {
super(props);
this.stateUpdater = this.stateUpdater.bind(this);
this.state = { canasta:[] };
}
render() {
return (
<View>
<RootNavigation data={[this.state, this.stateUpdater]} />
</View>
);
}
}
Menu.js
tryAddCanasta(index, plato){
let canasta = this.props.screenProps[0].canasta;
plato.id_Plato = canasta.length;
canasta.push(plato);
this.props.screenProps[1]('canasta', canasta);
}
Canasta.js
shouldComponentUpdate(nextProps, nextState) {
return true;
}
render() {
return (
<Container>
<Content>
<List>
{this.props.screenProps[0].canasta.map( (item) => {
return ( this._renderRow(item) );
})}
</List>
</Content>
</Container>
);
}
Special thanks to #Shadow_m2, now I don't need check every time, it works in "real time"
The most stupid thing is happening with my code right now. I have a list of items render in the DOM, I need to put a button in order to call another function, if I put the button like this <button></button> everything is ok, but if I assign a function to that button, then everything goes down <button onClick={function}></button> I will show you my code, look
#connectToStores
export default class Dealers extends Component {
static contextTypes = {
router : React.PropTypes.func,
}
static propTypes = {
title : React.PropTypes.func,
}
constructor (props) {
super(props);
this.state = {
modal : false,
}
}
static getStores () {
return [ GetDealersStore ];
}
static getPropsFromStores () {
return GetDealersStore.getState();
}
render () {
let dealersInfo;
if (this.props.dealerData !== null) {
dealersInfo = this.props.dealerData.dealersData.map(function(dealer) {
return (<div key={dealer.DealerId} style={Styles.dealerCard}>
<Card>
<CardHeader title={dealer.NickName}
subtitle={dealer.DealerId}
avatar={dealer.Picture}/>
<CardText>
<FloatingActionButton> ////////////////////////
<IconAdd /> //////THIS IS THE BUTTON/////
</FloatingActionButton>//////////////////////
</CardText>
</Card>
</div>
);
});
} else {
dealersInfo = <p>Loading . . .</p>;
}
return (
<Grid>
<Row>
<Column><h4>Dealers</h4></Column>
</Row>
<div style={Styles.mainCont}>
{dealersInfo}
</div>
</Grid>
);
}
componentWillMount () {
GetDealersActions.getDealers();
}
_openUpdateDealer = () => {
console.log(123);
}
}
as you can see there is an statement
if (this.props.dealerData !== null) {
...
}else {
dealersInfo = <p>Loading . . .</p>;
}
as I pasted the code above everything works awesome, but if I add <FloatingActionButton onClick={this._openUpdateDealer.bind(this)}><IconAdd /></FloatingActionButton> then everything goes down, all I see in the screen is Loading . . . which is the else in the statement above.
So, I want to know, what is going on with react here ?
You're rendering the button in the middle of a .map operation:
this.props.dealerData.dealersData.map(function(dealer) {
which uses a different value for this; thus, this.props doesn't exist inside the function. I would expect to see cannot read property dealerData of undefined in the browser console.
You need to use the optional thisArg parameter:
this.props.dealerData.dealersData.map(function(dealer) {
// ...
}, this);
bind the mapping function to this manually:
this.props.dealerData.dealersData.map(function(dealer) {
// ...
}.bind(this));
or use an arrow function (since you're using ES6 features):
this.props.dealerData.dealersData.map((dealer) => {
// ...
});