SetState in React ES6 - reactjs

I'm just learning React & I just can't seem to get setstate in the componentdidmount function to work. It would be adorable if you could help me out. I already tried to bind it.
I keep getting errors such as Cannot read property 'setState' of undefined.
class ShareEvent extends React.Component {
constructor(props) {
super(props);
this.state = {copied: false};
this.componentDidMount = this.componentDidMount.bind(this);
}
componentDidMount() {
var clipboard = new Clipboard('#copy-button');
clipboard.on('success', function (e) {
this.setState({copied: true});
e.clearSelection();
});
clipboard.on('error', function (e) {
document.getElementById("title").innerHTML = 'Please copy manually.';
});
}
handleChange(event) {
event.preventDefault();
event.target.select();
}
render() {
const EventURL = GenerateEventUrl(this.props.EventName,this.props.EventTimeUTC);
return (
<div>
<h1>{this.state.copied ? "Copied!" : "Nicely done." }</h1>
<p>Now, simply share the link below.<br />It will display{' '}
<a href={EventURL}>the event</a>{' '}
in the local time of whoever visits it.</p>
<form>
<div className="input-group">
<input onClick={this.handleChange} type="text" className="form-control" defaultValue={EventURL} readOnly id="copy-input" />
<span className="input-group-btn">
<button className="btn btn-default" type="button" id="copy-button" data-clipboard-target="#copy-input" title="Copy to Clipboard">
Copy
</button>
</span>
</div>
</form>
</div>
);
}
}

You need to bind the this that references your component to your function. Change
function (e) {
this.setState({copied: true});
e.clearSelection();
}
to
function (e) {
this.setState({copied: true});
e.clearSelection();
}.bind(this)
or use ES6 arrow functions, which automatically bind this
e => {
this.setState({copied: true});
e.clearSelection();
}

Related

Cannot read property 'state' of undefined in API call

I have the following component in react
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
cityName: "",
weather: ""
}
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
fetch(`https://api.weatherapi.com/v1/current.json?key=.....&q=${this.state.cityName}&aqi=no`)
.then(response => response.json())
.then(json => {
this.setState({ weather: json});
});
}
handleChange(event) {
this.setState({cityName: event.target.value});
}
render() {
return (
<center>
<p><font color="bluesky" size="10">Weather</font></p>
<div class="card-body">
<input type="text" value={this.state.value} onChange={this.handleChange} placeholder="Type the name of city"></input>
<h3>{this.state.cityName}</h3>
</div>
<div>
<button className="btn btn-secondary btn-sm" onClick={this.componentDidMount}>Check weather</button>
</div>
</center>
);
}
}
and for this line of code
fetch(`https://api.weatherapi.com/v1/current.json?key=...&q=${this.state.cityName}&aqi=no`)
I get the next error "TypeError: Cannot read property 'state' of undefined". I am new to react, can somebody help me to fix this error ?
You are calling component lifecycle method to handle form submit. Create a submitHandler just as you've the changeHandler and it should work fine.
onSubmit = () => {
fetch(`https://api.weatherapi.com/v1/current.json?key=.....&q=${this.state.cityName}&aqi=no`)
.then(response => response.json())
.then(json => {
this.setState({ weather: json});
});
}
The button will be configured as:
<button className="btn btn-secondary btn-sm" onClick={this.onSubmit}>Check weather</button>
Pro tip: Use arrow functions to define custom methods in your component.
Note: You need to configure the API key and handle the response correctly,use console.log(json) in the second .then() and see what you get.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
cityName: "",
weather: ""
}
}
onSubmit = () => {
fetch(`https://api.weatherapi.com/v1/current.json?key=.....&q=${this.state.cityName}&aqi=no`)
.then(response => response.json())
.then(json => {
this.setState({ weather: json});
});
}
handleChange = (event) => {
this.setState({cityName: event.target.value});
}
render() {
return (
<center>
<p><font color="bluesky" size="10">Weather</font></p>
<div class="card-body">
<input type="text" value={this.state.cityName} onChange={this.handleChange} placeholder="Type the name of city"></input>
<h3>{this.state.weather}</h3>
</div>
<div>
<button className="btn btn-secondary btn-sm" onClick={this.onSubmit}>Check weather</button>
</div>
</center>
);
}
}
componentDidMount() is a function where its code is executed when the component is mounted, so when you fetch data with in componentDidMount(), the ${this.state.cityName} in the URL is still equal to nothing (cityName: "" in your default state)
You need to set a default value to cityName like
this.state = {
cityName: "London",
weather: ""
}
or
You need to fetch only after the user pressed a button
search() {
// fetch here
}
<button className="btn btn-secondary btn-sm" onClick={this.search}>Check weather</button>
And by the way you need to remove onClick={this.componentDidMount} from the button because componentDidMount is automatically called when the component is mounting, better replace this by onClick={this.search} and create a search function where you can fetch datas

Why is React state not changing simultaneously with input change for a controlled component

I don't think I missed anything in making the form a controlled component. Why doesn't the state doesn't change as characters are being input?
class AddChores extends Component {
state = {
chore: "",
};
handleChange = (evt) => {
this.setState({ chore: evt.target.value });
};
handleSubmit = (evt) => {
evt.preventDefault();
this.props.addChores(this.state);
this.setState({ chore: "" });
};
render() {
console.log(this.state);
return (
<div>
<form onClick={this.handleSubmit}>
<input
type="text"
placeholder="New Chore"
value={this.state.chore}
onChange={this.handleChange}
/>
<button className="button">ADD CHORE</button>
</form>
</div>
);
}
}[![React dev tool showing no simultaneous update][1]][1]
I made some changes as below and it works fine for me. Hope it helps you too.
class AddChores extends Component {
constructor(props) {
super(props);
this.state = {
chore: ""
};
}
handleChange = (event) => {
this.setState({
chore: event.target.value
});
};
handleSubmit = (evt) => {
evt.preventDefault();
// this.props.addChores(this.state);
this.setState({ chore: "" });
};
componentDidUpdate(){
console.log('the state', this.state.chore)
}
render() {
return (
<div>
<form onClick={this.handleSubmit}>
<input
type="text"
placeholder="New Chore"
value={this.state.chore}
onChange={this.handleChange}
/>
</form>
</div>
);
}
}
not sure why is this happening but try using the second form of setState
this.setState(() => ({ chore: evt.target.value}))
check this https://reactjs.org/docs/state-and-lifecycle.html#state-updates-may-be-asynchronous

Why is this.setState not updating in my click function?

I am trying to update my state by using a click function. However for some reason it is not updating. Could someone please explain to me what I am doing wrong?class Textbox extends
Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'jkjkljkljl'
}
}
handle(event) {
const myValue = event.target.value;
this.setState({
text: myValue
})
console.log(this.state)
}
render() {
return (
<div>
<textarea className="Textbox" rows="2" cols="30" type = "text" >
</textarea>
<button className="postbutton" onClick={this.handle.bind(this)}>Post</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
export default Textbox;
Here is an updated version of your code that works.
Issue was that you were trying to set the value of the button to the state.
What you should do is setup textarea as a controlled input (have value and onChange setup as I did below) and use that value on click.
class Component extends React.Component {
constructor(props) {
super(props);
this.state = {
textArea: "",
text: "jkjkljkljl"
};
}
handle(event) {
console.log(event);
this.setState({
text: this.state.textArea
});
console.log(this.state);
}
handleChange(event) {
this.setState({ textArea: event.target.value });
}
render() {
return (
<div>
<textarea
className="Textbox"
rows="2"
cols="30"
value={this.state.textArea}
onChange={this.handleChange.bind(this)}
/>
<button className="postbutton" onClick={this.handle.bind(this)}>
Post
</button>
<h1>{this.state.text}</h1>
</div>
);
}
}
It seems you are trying to handle a form using React/JSX. There are great libraries for this purpose (React Forms).
This is the proper code:
class App extends React.Component {
constructor(props) {
super(props);
this.handle = this.handle.bind(this);
this.state = {
text: 'Static'
}
}
handleOnChange(event) {
this.setState({text: event.target.value});
}
handleSubmit(event) {
if (event.keyCode == 13) return this.sendData();
}
render() {
return (
<div>
<form onKeyUp={this.handleOnChange}>
<textarea className="Textbox"
rows="2" cols="30" type="text"
>
</textarea>
<button className="postbutton"
onClick={this.handleSubmit.bind(this)}>
Post
</button>
</form>
<h1>{this.state.text}</h1>
</div>
);
}
}
React.render(<App />, document.getElementById('app'));
In your example, you are binding the state to the root of the button and not the textarea. If you want a static example (whereas the above code changes as you type), you may simply handle the enter key via if (event.keyCode == 13) return this.sendData() and remove the onChange.

How does React class component method's parameters work?

I'm learning React and am having a hard time understanding how a class component's method parameters work. In the code below the handleAddOption method (which helps with adding items upon clicking a button, it's a to-do app) - it takes 'option' as parameter - but I do not see the arguments supplied in the render method.
Similarly in the AddOption component the handleAddOption has an argument 'option' - where is this coming from?
I'm a newbie to React and to stackoverflow as well, any norms I may not have followed please point out. Thanks for the help.
class App extends React.Component {
constructor(props) {
super(props);
this.handleAddOption = this.handleAddOption.bind(this);
this.state = {
options: []
};
}
handleAddOption(option) {
if (!option) {
return 'Enter valid value to add item';
} else if (this.state.options.indexOf(option) > -1) {
return 'This option already exists';
}
this.setState((prevState) => {
return {
options: prevState.options.concat(option)
};
});
}
render() {
return (
<div>
<div>{this.state.options.map((option) => <p>{option}</p>)}</div>
<AddOption handleAddOption={this.handleAddOption} />
</div>
);
}
}
class AddOption extends React.Component {
constructor(props) {
super(props);
this.handleAddOption2 = this.handleAddOption2.bind(this);
this.state = {
error: undefined
};
}
handleAddOption2(e) {
e.preventDefault();
const option = e.target.elements.option.value.trim();
const error = this.props.handleAddOption(option);
this.setState(() => {
return { error };
});
}
render() {
return (
<div>
{this.state.error && <p>{this.state.error}</p>}
<form onSubmit={this.handleAddOption2}>
<input type="text" name="option" />
<button>Add Option</button>
</form>
</div>
);
}
}
render(<App />, document.getElementById('app'));
The arguments are being passed by the submit handler attached to the form.
You provide a function that you want called whenever there is a submit event. The form will call whatever function you provide with the arguments it usually passes in.
This happens the same way as it happens in plain JS:
const form = document.getElementById("form");
form.addEventListener("submit", e => {
e.preventDefault();
console.log("submit 1");
});
const submitHandler = e => {
e.preventDefault();
console.log("submit 2");
};
form.addEventListener("submit", submitHandler);
<form id="form">
<input type="submit" />
</form>
Consider the React example:
class MyForm extends React.Component {
constructor(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
foo:""
}
}
handleSubmit(e) {
e.preventDefault();
console.log("MyForm Submit 1");
this.setState(state => ({
foo: "foo"
}));
}
render() {
/*
onSubmit will always call the function that is provided
with a submit event argument.
*/
return (
<form onSubmit={this.handleSubmit}>
<div>{this.state.foo}</div>
<input type="submit"/>
</form>
)
}
}
class MyOtherForm extends React.Component {
constructor(props){
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
foo:""
}
}
handleSubmit(e) {
e.preventDefault();
console.log("MyForm Submit 2");
this.setState(state => ({
foo: "bar"
}));
}
render() {
// Here we will pass the argument explicitly
return (
<form onSubmit={e => this.handleSubmit(e)}>
<div>{this.state.foo}</div>
<input type="submit"/>
</form>
)
}
}
const App = () => {
return(
<div>
<MyForm/>
<MyOtherForm/>
</div>
);
};
ReactDOM.render(<App/>, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
According to the code you provide, handleAddOption(option) is called from the handleAddOption2 function in the AddOption component.
handleAddOption2(e) {
e.preventDefault();
const option = e.target.elements.option.value.trim();
const error = this.props.handleAddOption(option);
this.setState(() => {
return { error };
});
}
You can see that option is e.target.elements.option.value.trim(). Now, where does e comes from? Tracking the source of the function above, you can see that handleAddOption2(e) is a event handler called from here:
<form onSubmit={this.handleAddOption2}>
<input type="text" name="option" />
<button>Add Option</button>
</form>
In React, event handlers (e.g. onClick/onSubmit) by default has a default event parameter embedded to its handler function. This parameter can be any name (defined by you), and the author of the code you provide named it e.
Giving you another example, say you have a button:
<button onClick={this.sayHello}>
Click me!
</button>
There is already an event param embedded to sayHello, but you can choose not to use it.
sayHello = () => {
alert('Hello!');
}
Or if you want to use it, I'll name it event instead of e here:
sayHello = (event) => {
event => alert(event.target.value)
}
Or you can choose define the event handler inline like this:
<button value="hello!" onClick={event => alert(event.target.value)}>
Click me!
</button>

React, onChange and onClick events fires simultaneously

I have a problem on my application: when a user is typing in the (and onChange is fired I suppose), even one single letter, the onClick event below is fired. Where is my mistake?
I have simplified the code over and there (where you see the comments), there no relevant code in there!
Thanks to everyone!
class Project extends React.Component {
constructor() {
super();
this.state = {
section_title: '',
sections: []
}
this.handleChange = this.handleChange.bind(this);
this.createSection = this.createSection.bind(this);
this.getSections = this.getSections.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
createSection(project_id) {
if(this.state.section_title != '') {
//Do Something here
}
}
getSections(project_id) {
//Fetch data here
}
componentDidMount() {
let project_data = this.props.project[0];
this.getSections(project_data.uid);
}
render() {
let project_data = this.props.project[0];
return (
<div>
<h2 className="ui header">
<i className="folder outline icon"></i>
<div className="content">
{project_data.title}
<div className="sub header">{he.decode(project_data.description)}</div>
</div>
</h2>
<div className="ui divider"></div>
<Modal trigger={<Button color="teal">Add New Section</Button>} closeIcon>
<Modal.Header>Add new section</Modal.Header>
<Modal.Content image>
<Modal.Description>
<Form>
<Form.Field>
<label>Section Name</label>
<input name="section_title" placeholder='Es: Slider ecc...' value={this.state.section_title} onChange={this.handleChange} />
</Form.Field>
<Button color="green" type='submit' onClick={this.createSection(project_data.uid)}>Crea Sezione</Button>
</Form>
</Modal.Description>
</Modal.Content>
</Modal>
</div>
);
}
}
in your Button you are initializing function this.createSection(project_data.uid) instead of calling it when needed. Easiest way is to call via arrow function
onClick={() => this.createSection(project_data.uid)}
What you did is basically using the return data of your createSection function for your onClick
So, on your onClick, try
onClick={() => this.createSection(project_data.uid)}
The onChange part is already correct.
This problem is similar to an existing answered question: React onClick function fires on render

Resources