I get Cannot GET /[object%20Object] on button click in React - javascript

I am new to React and learning click events. But the issue I faced is that one button click I get "Cannot GET /[object%20Object]". Here is the code I am using:
class Engine extends React.Component {
render() {
let types = ["Diesel", "Gazoline"];
return (
<div>
<Car type={types} />
</div>
);
}
}
class Car extends React.Component {
open() {
console.log("You have clicked");
}
render() {
return (
<div>
<h1>
{this.props.type.map((item, index) => {
return <p key={index}>{item}</p>;
})}
</h1>
<button onClick={open}>Remove all</button>
</div>
);
}
}
const box = document.querySelector(".mir");
ReactDOM.render(<Engine />, box);

You need to use this.open, since it doesn't know exactly what you're referring to by open :
<button onClick={this.open}>Remove all</button>
If you were to have named the function, say, foo instead of open, then it wouldn’t have worked at all.
The reason why you're seeing the functionality is because it is using the default open command built into JavaScript, which opens a new page. Under the hood, clicking the button is calling open(e) where e is the button event. So it's trying to open a new page, but instead of it receiving a URL, it's receiving an object, and thus you're seeing the error you received.
Instead, you want to use the open that is defined in the class. In order to do that, you need to use this.open.
In addition, if you want to pass something to the function as an argument, you'll need to change it a bit.
You can change open to:
open = (myparam) => {
console.log("You have clicked");
console.log(myparam);
}
In order to bind this. Then you can do something like:
<button onClick={_ => this.open("foo")}>Remove all</button>

You need to bind the open function to component and also call it with 'this'.
Or you can make the arrow function.
<button onClick={this.open.bind(this)}
or
open = () => { ... }
<button onClick={this.open}

Related

Pass onClick handler and prevent default behavior of button in React

I am new to React/Next development. I have the code below:
import React from "react";
const Car = () => {
var carCounter = 0;
function addCar(event) {
event.preventDefault();
carCounter++;
console.log(carCounter);
}
return (
<form>
<span className="car">
<button class="big-button" onClick={addCar()}>
Add Car
</button>
</span>
</form>
);
};
export default Car;
Obviously, this code is simplified. The root of my error was that the form was submitting when I pressed the button. However, the purpose of the button was to not "submit" the form. Rather, it was to increment a counter.
This is the error that was thrown above:
TypeError: Cannot read property 'preventDefault' of undefined
I went based of this thread:
https://stackoverflow.com/questions/39809943/react-preventing-form-submission#:~:text=Simply%20add%20onSubmit%3D%7BhandleSubmit,stop%20the%20default%20submission%20behavior.
Let me know what I can do!
When providing onClick handler to the button, you need to write:
<button class="big-button" onClick={addCar}>Add Car</button>
// removed the () in addCar ^
Then, it will pass the event to the addCar method.

"Reset" button won't work unless it refreshes page, and gives me an error otherwise (React.JS)

So I'm working in React.JS, and I'm trying to make something like an input field, where a user can enter a number of their choice, and it will show up in the text.
I decided to add a "Reset to zero" button, as an extension.
<div>
Count: {this.state.value}
<form>
<input type="number" value = {this.state.value} onChange = {this.inputChange}/>
<br/>
<button onClick = {this.reset}>reset to zero</button>
</form>
</div>
It works, but it refreshes the page every time it does so.
I read online, and I decided to add "type=button" to my button as so:
<button type="button" onClick = {this.reset}>reset to zero</button>
When I run my code again, it still increments fine, but when I click the button, nothing happens, and when I try to increment it again, I get an error, "TypeError: this.setState is not a function".
The error is coming from this method:
inputChange = event => {
this.setState ({value: event.target.value})
}
I know where the error is coming from, but I don't know why it happened, or how to fix it (note that I'm also a beginner at JavaScript and React.JS)
I hope someone can help me.
Here's my code in entirety, for reference.
class Slider extends React.Component {
constructor(props){
super(props);
this.state = {
value: 0
}
}
inputChange = event => {
this.setState ({value: event.target.value})
}
reset = () => {
this.setState = ({
count: 0
})
}
render() {
return (
<div>
Count: {this.state.value}
<form>
<input type="number" value = {this.state.value} onChange = {this.inputChange}/>
<br/>
<button type = "button"onClick = {this.reset}>reset to zero</button>
</form>
</div>
);
}
}
Thank you guys, in advance.
The reason nothing happens on reset and you are getting that error on input change, is that you are reassigning this.setState in your reset function rather than calling it. Also, you are setting count instead of value, which would lead to the wrong state being set.
This is what your reset function should be:
reset = () => {
this.setState ({
value: 0
})
}
When you call this.setState, React will trigger a re-render in your component with the new state.
That is currently not happening when you click reset. On your subsequent call to inputChange, this.setState has been reassigned with an object, and is no longer callable, throwing that error.
Try replacing your button like this:
<button type = "button"onClick = {this.reset.bind(this)}>reset to zero</button>
This will force the method to execute being this the scope.

React : test a function which is passed as a props and is triggered by the parent

I'm trying to trigger a click event for my test. As this :
describe('Button', function() {
test('is clicked when player two is pending', (props ={}) => {
const mockRandomAdv = sinon.spy();
const tree = shallow(
<FightButton
button="Random adversary"
isPlayerTwoPending={true}
isPlayerOnePending={false}
onClick={mockRandomAdv}
/>
);
tree.find('Button').simulate('click');
//expect(mockRandomAdv.calledOnce).toEqual(true);
console.log(tree.props().children.onClick)
//.not.toBe('fight-button random');
});
});
The first expectation return false so the click is not triggered.
When i console.log() the click event it returns undefined.
Here is my child (which is not the last last child).
<Button
onClick={ () => { this.props.randomAdversary }}
class="fight-button random"
button="Random adversary"
/>
And here is the parent that is calling the child and who describe the method :
class Board extends Component {
constructor(props) {
..my constructor
}
randomAdversary() {
...my function
}
return (<div> <FightButton
isPlayerTwoPending={this.state.adversaryPending}
isPlayerOnePending={this.state.characterPending}
isPlayerOneTheWinner={this.state.heroWin}
isFighting={this.state.fighting}
randomAdversary={this.randomAdversary}
fight={this.fight(100)}
playAgain={this.playAgain()}
/>
</div>
)
}
When i click, the class of my button must change. But the same when i console.log the class, it has no changed. Is something wrong with my test ?
Looking at the button, I don't see calling the function correctly. I'ts actually doing nothing, you need to execute the function like this:
<Button
onClick={ () => { this.props.randomAdversary() }} // Add the `()`
class="fight-button random"
button="Random adversary"
/>

onClick function is running on another event listener

Have been playing around with react. Have two event listeners the input which listens onChange and the button which should push the value to the array when its clicked.
Here's the code:
import React, { Component } from 'react';
let arr = [];
class App extends Component {
constructor() {
super();
this.state = {text: 'default'}
}
update( e ) {
this.setState({text: e.target.value})
}
add ( value ) {
arr.push(value)
console.log(arr)
}
render() {
return (
<div>
<h1>{this.state.text}</h1>
<input onChange={this.update.bind(this)}/>
<button onClick={this.add(this.state.text)}>Save</button>
</div>
)
}
}
export default App
The problem that the add function is running on change. Can't really get why.
Any suggestions?
onChange() triggers update()
update() calls this.setState() which changes state.
A state change causes render() to be invoked to re-render according to new state.
Rendering <button onClick={this.add(this.state.text)}>Save</button> invokes add() every time render() runs.
In order to defer invoking add(), you can define a function which gets triggered by the click event, as was shown in another answer. Alternatively, you can achieve the same functionality by adding a class method which encapsulates the trigger functionality:
addText() {
this.add(this.state.text)
}
render() {
…
<button onClick={this.addText.bind(this)}>Save</button>
This may or may not work for you, but in the context of the example, given, this would work.
Change <button onClick={this.add(this.state.text)}>Save</button>
To <button onClick={() => this.add(this.state.text)}>Save</button>
In your variant function add firing when component is rendering, and when you call setState with onChange of input you call this re-render.
The problem is add(this.state.text) is called whenever render() is called. To avoid this, you do not need to send the state as parameter, all you need to do is
<button onClick={this.add}>Save</button
or if you want to send a parameter you should bind it
<button onClick={this.add.bind(this, this.state.text)}>Save</button>

How to pass an event handler to a child component in React

I have a <Button /> component I've created in React that abstracts out some of the styling in my application. I am using it in two different contexts - one to submit a login form, and the other to navigate to the registration page (and probably other contexts in the future).
I am trying to figure out how to pass the event handlers from the parent component to the <Button />. I want to call an onSubmit handler for the login form, but an onClick handler for the navigation button. Is this possible?
I have tried calling the component like this:
<Button text={callToAction} style={styles.callToActionButton} onClick={() => FlowRouter.go("Auth")}/>
<Button text="Go!" style={styles.registerButton} onSubmit={() => this.register(this.state.user, this.state.password)}/>
I've also tried removing the arrow function, which just causes the functions to execute when the component is loaded:
// executes event handlers on page load
<Button text={callToAction} style={styles.callToActionButton} onClick={FlowRouter.go("Auth")}/>
<Button text="Go!" style={styles.registerButton} onSubmit={this.register(this.state.user, this.state.password)}/>
In general, you can forward the onClick handler to your button class by passing it as a property. You could this make a required prop by simply defining the propTypes for your button component.
As an example, I added a small snippet that shows how it works
var StyledButton = React.createClass({
propTypes: {
// the StyledButton requires a clickHandler
clickHandler: React.PropTypes.func.Required,
// and I guess the text can be seen as required as well
text: React.PropTypes.string.required
},
render: function() {
// as you are sure you have a clickHandler, you can just reference it directly from the props
return <button type="button" onClick={this.props.clickHandler}>{this.props.text}</button>;
}
});
var MyForm = React.createClass({
getInitialState() {
return {
clicked: 0
};
},
click() {
this.setState({clicked: this.state.clicked+1});
alert('ouch');
},
secondClickHandler() {
this.setState({clicked: 0});
alert(':(');
},
render() {
// your parent component simply sets which button
return <fieldset>
<div>
<StyledButton clickHandler={this.click} text="Click me" />
{ (this.state.clicked > 0) && <StyledButton clickHandler={this.secondClickHandler} text="Not again" /> }
</div>
</fieldset>;
}
});
ReactDOM.render(
<MyForm />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.2/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Also, you wouldn't in general use the submit method of a button, you would rather send the data received to a webservice, and handle any changes when the result is received. The submit kills the current website and needs to load everything anew, while with an ajax call, or a store, it can just wait for the result and then redirect the user based on the response
How we have handled this is we have a button component that renders an a tag and then we have a href prop and a onClick prop you can pass in. If its a link just pass in the href prop to the button and if you are wanting it to execute a function just pass it in an onClick prop and make sure it gets set on the a tag.
In the Button component we also setup a custom onClick function that looks like this:
_onClick: function(e) {
if (!this.props.onClick) {
return;
}
this.props.onClick(e);
}
and then on the a tag
<a href={this.props.href} onClick={this._onClick} />

Categories