Can't call function onSubmit from embedded form element [duplicate] - javascript

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) => {
// ...
});

Related

Return JSX from component method to render method

I'm still new to React. I'm trying to render a jsx under a condition defined in another method under my class component like so:
isWinner = () => {
let userVotesCount1 = this.state.user1.userVotesCount;
let userVotesCount2 = this.state.user2.userVotesCount;
if (userVotesCount1 > userVotesCount2) {
userVotesCount1++;
this.setState({ user1: { userVotesCount: userVotesCount1 } });
return (
<h3>Winner</h3>
);
}
userVotesCount2++;
this.setState({ user2: { userVotesCount: userVotesCount2 } });
return (
<h3>Loser</h3>
);}
and i'm calling this method inside the render method
<Dialog
open={open}
onRequestClose={this.onClose}
>
<div>
<isWinner />
</div>
</Dialog>
already tried to use replace <isWinner /> for {() => this.isWinner()}and I never get the return from the method. What I am doing wrong? Since I'm dealing with state here I wouldn't know how to do this with outside functions. For some reason this function is not being called ever. Please help!
You're almost there. What you want to do is use the method to set a flag, and then use the flag in the render method to conditionally render.
constructor(props) {
...
this.state = {
isWinner: false,
...
}
}
isWinner() {
...,
const isWinner = __predicate__ ? true : false;
this.setState({
isWinner: isWinner
});
}
render() {
const { isWinner } = this.state;
return isWinner ? (
// jsx to return for winners
) : (
// jsx to return for lossers
)
}

ref is not defined using arrow function in react?

I try to make a toggleable content when user clicked on outside of the element I got error of this.node is not defined error?
handleOutsideClick(e) {
// ignore clicks on the component itself
if (this.node.contains(e.target)) {
return;
}
this.handleClick();
}
render() {
return (
<div ref={node => { this.node = node; }}>
<button onClick={this.handleClick}>Button handler</button>
{this.state.visibleContent && <div>Toggle content</div>}
</div>
);
}
Code https://codesandbox.io/s/v38q4zrq7
In the render method I've used ref={node => { this.node = node; }} why is it still undefined? Here's a working example that used exactly the same technique https://codepen.io/graubnla/pen/EgdgZm
Your function handleOutsideClick is out of scope. If you're using babel, you can turn it into an arrow function directly
handleOutsideClick = (e) => {
// ignore clicks on the component itself
if (this.node.contains(e.target)) {
return;
}
this.handleClick();
}
or if that is not an option, bind it in your constructor
constructor() {
super()
this.handleClick = this.handleClick.bind(this)
}

React: How can I render multiple menus with map() without causing a re-render?

I have a component called <SiteMenu />. Inside of my render function I have these three lines:
render() {
{ this.renderPrimaryMenu() }
{ secondaryMenuContents && this.renderSecondaryMenu() }
{ this.renderAdditional() }
}
Each of those have a corresponding function that maps through results and creates menus as unordered list. A boiled-down version:
renderAdditional() {
const { secondaryMenuContents } = this.props;
if (!secondaryMenuContents) { return false; }
const additional = filter(secondaryMenuContents.sections, { additional: true });
if (!additional || additional.length === 0) { return false; }
const links = additional.map(
(link, index) => {
return (
<Link
key={ `${index}-${link.link}` }
to: link.link
>
{ link.text }
</Link>
);
}
);
return (
<nav className={ styles['nav--additional'] }>
<Responsive>
<h3 className={ styles.h3 }>{ Lang.additionalSection.title }</h3>
<menu className={ styles['menu--additional'] }>
{ links }
</menu>
</Responsive>
</nav>
);
}
Each time one of these lists is rendered it re-renders the entire component. One of the menus uses static JSON (renderPrimaryMenu()) while the other two depend on data in two separate calls from an API, so that data doesn’t always come in at the same time.
Any suggestions for ensuring a single render OR, even better, having the first static menu (which fades in and re-fades in with every render) display and the other two render when they’re ready without causing the first menu to re-render?
Appreciate any help I can get!
I suggest you to separate these three components.
And use shouldComponentUpdate() to ensure whether to rerender the component.
This is the pseudo-code:
class PrimaryMenu extends Component {
shouldComponentUpdate() {
// if data is the same, return false
// else return true
}
render() {
return (
...
)
}
}
class SecondaryContent extends Component {
// same logic as PrimaryMenu
}
class Additional extends Component {
// same logic as PrimaryMenu
}
class SiteMenu extends Component {
render() {
return (
<PrimaryMenu/>
<SecondaryContent/>
<Additional/>
)
}
}
So with this setup, you can control the re-render time at each Menu.
or try PureComponent, it exists to reduce re-rendering stuff.
import React, { PureComponent } from 'react';
class Additional extends PureComponent {
}
More info
https://reactjs.org/docs/react-api.html#reactpurecomponent

Call parent component function from child in React.JS

I am trying to make a simple component in React.JS which displays a list of items, then the user can select an item from the list. I am trying to handle the clicks on the list-items by handing down a function from the parent component to the child, so it can notify the parent when it was clicked and the parent can update the selected item. For some reason the function from the child component is not calling the parent function properly as it never gets to the point to write to the console ... I guess it must something to do with binds, but I literally tried every combination possible to make it work.
Tbh, I don't even understand why I have to use "clicked={()=>this.clickedSub}" in the parent component when I already used bind in the constructor, but I guess I don't have to understand everything XD
var months = [
'January','February','March','April','May','June','July','August','September','October','November','December'
];
class SubItem extends React.Component {
constructor(props){
super(props);
this.clickedMe = this.clickedMe.bind(this);
}
clickedMe () {
let i = this.props.id;
console.log("from child: "+i);
this.props.clicked(i);
}
render () {
if (this.props.isSelected) return <a href="#" className="selected" onClick={this.clickedMe}>{this.props.text}</a>;
else return <a href="#" onClick={this.clickedMe}>{this.props.text}</a>;
}
}
class SideMenu extends React.Component {
constructor() {
super();
this.state = {
selected: 0,
open: true
};
this.clickedHead = this.clickedHead.bind(this);
this.clickedSub = this.clickedSub.bind(this);
}
clickedHead () {
this.setState({
open: !this.state.open
});
}
clickedSub(i) {
console.log("from parent:"+i);
this.setState({
selected: i
});
}
render() {
let sel = this.state.selected;
var sublist = this.props.subitems.map(function (item, index){
if (index==sel) return <SubItem text={item} isSelected={true} id={index} clicked={()=>this.clickedSub}/>;
else return <SubItem text={item} isSelected={false} id={index} clicked={()=>this.clickedSub}/>;
});
if (this.state.open) return (
<div className="side_menu">
<div className="menu_item open">
<div className="header" onClick={this.clickedHead}>{this.props.header}</div>
<div className="sub_items">
{sublist}
</div>
</div>
</div>
);
else return(
<div className="side_menu">
<div className="menu_item open">
<div className="header" onClick={this.clickedHead}>{this.props.header}</div>
<div className="sub_items"></div>
</div>
</div>
);
}
}
ReactDOM.render(
<SideMenu header="Month" subitems={months}/>,
document.getElementById('menu')
);
See the Pen vertical collapsible side-menu by Ize8 on CodePen.
Alright, so I struggled with this one for a little while. You have to be really careful when you do NOT use es6 in react. Arrow functions are your friend, and generally just make more sense.
This is where all your trouble is coming from:
var sublist = this.props.subitems.map(function (item, index){
if (index==sel) return <SubItem text={item} isSelected={true} id={index} clicked={()=>this.clickedSub}/>;
else return <SubItem text={item} isSelected={false} id={index} clicked={()=>this.clickedSub}/>;
});
You want to use arrow functions here because you're messing with the scope. You can pass down the function as intended, and you do not have to do this clicked={() => this.clickedSub} syntax which is confusing.
var sublist = this.props.subitems.map((item, index) => {
if (index==sel) return <SubItem text={item} isSelected={true} id={index} clicked={this.clickedSub}/>;
else return <SubItem text={item} isSelected={false} id={index} clicked={this.clickedSub}/>;
});
This will pass down your function as intended, but you have some other issues with your code. It causes an infinite loop, but I'll let you implement this and work through it.
First of all if you don't wont to have .bind(this) in constructor use an arrow function
clickedSub(i){} it is clickedSub = (i)=>{}
Now. I don't get what function you pass to the children. but I will show you an example.
class Parent extends Component {
constructor() {...}
parentFunction = () => {
console.log('This will be called when we click `a` tag in Child component');
}
render() {
return (
<Child funct = {this.parentFunction}/>
)
}
}
class Child extends Component {
handleClick = () => {
this.props.func();
}
render() {
return(
<a onClick={this.handleClick}> Click me </a>
)
}
}

React/material ui raisedbutton executing onTouchTap on init

I am using react/redux/material ui and normally through out my website the components work fine. One 1 page there is something very very wierd going on.
I create a component like this:
class MyOwnComponent extends Component {
doSomething = (id) => {
alert('doSomething: id = ' + id )
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap={this.doSomething(id)}/>
)
}
}
I have a raisedbutton from material ui and put it in the render method.
The thing is that when the page loads with the component in it the doSomething method is called. Even though it is only called in the onTouchTap in raisedbutton. Almost as if a bug in the raisedbutton is calling the onTouchTap method immediately instead when the button is clicked.
Does any body have a explanation for this really strange behaviour?
Thanks
You are giving to onTouchTap void, because that's what this.doSomething(id) returns .
this.doSomething(id)
is executed the firs time MyOwnComponent is rendered.
Instead you should do this :
class MyOwnComponent extends Component {
doSomething = () => {
const {id} = this.props.object;
alert('doSomething: id = ' + id )
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap={this.doSomething}/>
)
}
}
The problem was that the return value of doSomething() function is returned and assigned to onTouchTap. Instead you should just pass the function name, without paranthesis.
One solution can be this.
class MyOwnComponent extends Component {
doSomething = () => {
alert('doSomething: id = ' + this.props.object.id );
}
render() {
return (
<RaisedButton secondary={true} label={'My label'} onTouchTap=
{this.doSomething}/>
);
}
}
Alternatively you can use also use
<RaisedButton secondary={true} label={'My label'} onTouchTap={()=>
this.doSomeThing(id) /> // eslint-disable-line
I tried your sollution. However when I use onTouchTap={() => this.doSomething(id)} the page wont load because the browser says JSX props should not use arrow functions.
And the id is from the props. At the top of the render method I say
const { id } = this.props.object

Categories

Resources