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
Related
I'm working on a CV Generator and I don't know how to properly append the school and field of study values to a new div inside React.
Using the onSubmit function I'm able to get the values after filling them out and clicking save, but I can't figure out where to go from here.
Update
What I want to do is take the values from the input and create a new div above the form that displays those values. For example, I want the School value to show
School: University of Whatever
And the same goes for Field of Study.
Field of Study: Whatever
I know how to do this in vanilla JS but taking the values and appending them to the DOM but it doesn't seem to work that way in React.
class Education extends Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit = (e) => {
e.preventDefault();
const schoolForm = document.getElementById("school-form").value;
const studyForm = document.getElementById("study-form").value;
};
render() {
return (
<>
<h1 className="title">Education</h1>
<div id="content">
<form>
<label for="school">School</label>
<input
id="school-form"
className="form-row"
type="text"
name="school"
/>
<label for="study">Field of Study</label>
<input
id="study-form"
className="form-row"
type="text"
name="study"
/>
<button onClick={this.onSubmit} className="save">
Save
</button>
<button className="cancel">Cancel</button>
</form>
)}
</div>
</>
);
}
}
export default Education;
You should use state in order to save the values then show it when the user submits.
import React from "react";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { scool: "", study: "", showOutput: false };
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit = (e) => {
e.preventDefault();
this.setState({
showOutput: true
});
};
setStudy = (value) => {
this.setState({
study: value
});
};
setSchool = (value) => {
this.setState({
school: value
});
};
render() {
return (
<>
<h1 className="title">Education</h1>
<div id="content">
{this.state.showOutput && (
<>
<div>{`school: ${this.state.school}`}</div>
<div>{`study: ${this.state.study}`}</div>
</>
)}
<form>
<label for="school">School</label>
<input
id="school-form"
className="form-row"
type="text"
name="school"
onChange={(e) => this.setSchool(e.target.value)}
/>
<label for="study">Field of Study</label>
<input
id="study-form"
className="form-row"
type="text"
name="study"
onChange={(e) => this.setStudy(e.target.value)}
/>
<button onClick={this.onSubmit} className="save">
Save
</button>
<button className="cancel">Cancel</button>
</form>
)
</div>
</>
);
}
}
export default App;
I have also added 2 functions to set state and a condition render based on showOutput.
You don't append things to the DOM in react like you do in vanilla. You want to conditionally render elements.
Make a new element to display the data, and render it only if you have the data. (Conditional rendering is done with && operator)
{this.state.schoolForm && this.state.studyform && <div>
<p>School: {this.state.schoolForm}</p>
<p>Field of Study: {this.state.studyForm}</p>
</div>}
The schoolForm and studyForm should be component state variables. If you only have them as variables in your onSubmit, the data will be lost after the function call ends. Your onSubmit function should only set the state, and then you access your state variables to use the data.
Do not use document.getElementById. You don't want to use the 'document' object with react (Almost never).
You can access the element's value directly using the event object which is automatically passed by onSubmit.
handleSubmit = (event) => {
event.preventDefault();
console.log(event.target.school.value)
console.log(event.target.study.value)
}
I need to Create a webpage with a textbox and a button. Enter any mathematical expression on the textbox and click the button, the result of the expression will be shown in an alert window. For example, enter 2+3-1 and click the button. It should show 4 in the alert window. I need to use ReactJS to create the webpage.
import React from 'react';
class Addition extends React.Component{
constructor(){
super();
this.state={
num1:'',
num2:'',
total:''
}
}
handlenum1 = (event) => {
this.setState({
num1:event.target.value
})
}
handlenum2 = (event) =>{
this.setState({
num2:event.target.value
})
}
exe = (event) => {
this.setState({total:parseInt(this.state.num1) +
parseInt(this.state.num2)});
event.prevent.default();
}
render(){
return(
<div>
<h1> Addition </h1>
<form onSubmit={this.exe}>
<div>
Number 01:
<input type="text" value={this.state.num1} onChange={this.handlenum1}/>
</div>
<div>
Number 02:
<input type="text" value={this.state.num2} onChange={this.handlenum2}/>
</div>
<div>
<button type= "submit"> Add </button>
</div>
</form>
{this.state.total}
</div>
)
}
}
export default Addition;
Make this changes in your onClick event exe
exe = (event) => {
event.preventDefault();
this.setState(
{
total: parseInt(this.state.num1) + parseInt(this.state.num2),
},
() => {
alert(this.state.total);
}
);
};
setState accepts a callback as its second argument, it makes setState synchronous in nature.
If you want to know more about setstate, Then refer this https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296
And you wrote event.prevent.default(); in your "onClick event exe", I'm afraid it is event.preventDefault();
For more information https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault
So my problem is simple I guess, I want that when I click an element, my input got the focus in, so this is my methods and constructor on my component :
constructor(props) {
super(props);
this.textInput = React.createRef();
this.state = {
searchValue: ""
};
}
activateSearchZone = action => {
this.props.activateSearchZone(action);
console.log(this.textInput);
this.textInput.current.focus();
};
handleSearchZone = event => {
let searchValue = event.target.value;
this.props.searchForUsers(searchValue, { isSearching: true });
setTimeout(() => {
this.props.searchForUsers(searchValue, {
isSearching: false,
searchDone: true
});
}, 1000);
this.setState({
searchValue
});
};
And this is my component :
{this.props.searchList.activated && (
<div className="search-bar__zone">
<FontAwesomeIcon icon={faSearch} size="xs"></FontAwesomeIcon>
<input
placeholder="Search"
onChange={event => this.handleSearchZone(event)}
value={this.state.searchValue}
type="text"
ref={this.textInput}
></input>
<FontAwesomeIcon
icon={faTimesCircle}
onClick={() => this.activateSearchZone(false)}
></FontAwesomeIcon>
</div>
)}
The console log shows that the current value is null, I understand now why, it is because my element is just rendered I think, but I want the focus in my input when clicking.
How can I do that ?
An help would be much appreciated.
You can focus an input element with autofocus attribute. In react, it will be like <input type="text" autoFocus />, this will do the job.
For detailed explanation, please refer the link https://davidwalsh.name/react-autofocus
That's because react doesn't knows about the ref on initial render. You need to use forwardRef. It is HOC that wraps your component and tells react that there is some ref. And it will not render that until it is available. Here is an example:
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
I have a page where a user can search a database for a given condition, then the data is returned with another button that the user can use to add information back to the database. However whenever I click on the second button, the page reloads. I can't get so much as a console.log to go in. I'm new to react and could use any help at all.
import React , { Component } from 'react';
import { database } from '../firebase';
const byPropKey = (propertyName, value) => () => ({
[propertyName]: value,
});
class Search extends Component{
constructor(props) {
super(props);
this.state={
users: null,
searchCondition: "",
friend: ""
}
// this.setState = this.setState.bind(this);
}
onSubmit = (event) => {
let {
searchCondition,
friend
} = this.state;
database.searchConditions(searchCondition).then(snapshot =>
this.setState(() => ({ users: snapshot.val() }))
);
event.preventDefault();
}
messageSubmit = (event) => {
console.log("Click")
}
render(){
let {
users,
searchCondition,
friend
} = this.state;
return(
<div>
<h1>Search for conditions</h1>
<form onSubmit={this.onSubmit}>
<div className="search">
<input
value={searchCondition}
onChange={event => this.setState(byPropKey('searchCondition', event.target.value))}
type="text"
placeholder="Condition to Search For"
/>
<button className="friendButton"
onClick="x"
type="submit">
Search
</button>
</div>
</form>
{!!users && <UserList users={users} />}
</div>
)
}
}
let UserList = ({ users, message }) =>
<div>
<h2>List of Usernames and Conditions of your Search</h2>
{Object.keys(users).map(key =>
<div key={key}>{users[key].username} : {users[key].condition}
<form>
<div className="search">
<input
value={message}
onChange={console.log("test")}
type="text"
placeholder="Message for this User"
/>
<button className="messageButton"
onClick={console.log(message)}
type="submit">
Message
</button>
</div>
</form>
</div>
)}
</div>
export default Search;
Have you tried to place the event.preventDefault() at the beginning of the event handler?
It should prevent the default behaviour imediately as the event gets fired.
Hope it works!
a couple things i can see, youre even.preventDefault() should be at the top of the page, you said it was reloading so thats unwanted behavior. second you should set state within the then, generally speaking in my experience that doesnt work- i believe due to setState being asynchronous or something of that nature.
i would rewrite your submit like this
onSubmit = (event) => {
event.preventDefault();
let {
searchCondition,
friend
} = this.state;
let value;
database.searchConditions(searchCondition).then(snapshot =>
value = snapshot.val
);
this.setState(() => ({ users: value) }))
}
also likely the reason your "messageSubmit()" was not console logging is because youre using a submit handler not a click handler so everytime your clicked you were reloading the page.
cheers
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();
}