After pushing submit button I use fetch button to get information about git user from git api. After information is fetched I write it to database and then setState with userIsFetched: true and then conditionally render components.
The problem is that after I change state userIsFetched: true I see for a second my <Chat /> component, but then I see <Signup /> component. In the console I see that the state is erased. If I use xmlhttprequest then it works fine. Why this is happening?
var database = firebase.database();
/*function readData() {
return firebase.database().ref('users/0dc2074d-f7db-4746-91bd-d6e61498b666').once('value')
.then((data)=>data.val())
}*/
class Chat extends React.Component {
render() {
return (<div>
<div className="row">
<div className="col">header</div>
</div>
<div className="row" >
<div className="col-10">one</div>
<div className="col-2">two</div>
</div>
<div className="row">
<div className="col">footer</div>
</div>
</div>)
}
}
class SignIn extends React.Component {
constructor(props) {
super(props);
this.state = {
signLogin: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleSubmit() {
this.props.handleSignInSubmit(this.state.signLogin);
}
handleChange(event) {
this.setState({
signLogin: event.target.value
})
}
render() {
return (<div>
<form className="form-signin" onSubmit={this.handleSubmit}>
<h2 className="form-signin-heading">Please sign in</h2>
<br/>
<label className="sr-only">Name</label>
<input type="text" className="form-control" placeholder="Name" required="" autoFocus="" onChange={this.handleChange} value={this.state.value}/>
<br/>
<button className="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
}
this.handleSignInSubmit = this.handleSignInSubmit.bind(this);
}
handleSignInSubmit(signLogin) {
fetch(`https://api.github.com/users/${signLogin}`)
.then((response)=>response.json())
.then((user)=>this.writeUserData(uuidv4(), user.name, user.avatar_url))
.then(()=>this.setState({userIsFetched: true}))
.catch( alert );
}
writeUserData(userId, userName, userAvatarUrl) {
firebase.database().ref('users/' + userId)
.set({
userName: userName,
userAvatarUrl : userAvatarUrl
});
}
render() {
console.log(this.state)
return this.state.userIsFetched ? <Chat /> : <SignIn handleSignInSubmit={this.handleSignInSubmit}/>
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
Here is the working example: https://codepen.io/RinatRezyapov/pen/WEEqJW
try enter RinatRezyapov and click Submit.
I've forgotten to add
event.preventDefault();
In SignIn's submit
handleSubmit() {
this.props.handleSignInSubmit(this.state.signLogin);
}
Now it works
handleSubmit(event) {
event.preventDefault();
this.props.handleSignInSubmit(this.state.signLogin);
}
Related
I have a form. When I enter something there and click on "submit", I want my app to add a new component which must include this one input everytime when I click on "submit".
export default class AddForm extends Component{
constructor(props){
super(props);
this.state = {
input: '',
obj: [],
}
this.onHandleChange = this.onHandleChange.bind(this);
this.onHandleSubmit = this.onHandleSubmit.bind(this);
}
onHandleChange(e){
this.setState({
input: e.target.value
});
}
onHandleSubmit(){
this.state.obj.push(this.state.input);
this.setState({
input: ''
})
}
render(){
return(
<div className = 'adder'>
<h1 className = 'header'>Enter the type of tasks you need to be done:</h1>
<div>
<form>
<input className = 'board-add' onSubmit = {this.onHandleSubmit} onChange = {this.onHandleChange} type = 'search' name = 'textarea' placeholder = 'How shall we call the board?'/>
<p><button className = 'cancel'>CANCEL</button>
<button onClick = {this.onHandleSubmit} className = 'create'>CREATE</button></p>
</form>
</div>
{this.state.obj.map((item) => <TaskBoard taskType = {item} />)}
</div>
);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
this.state.obj.push(this.state.input);
^ This is not good practice in React. instead do this
obj: [...this.state.obj, this.state.input],
For more information on ... stuff check out the link below
https://medium.com/coding-at-dawn/how-to-use-the-spread-operator-in-javascript-b9e4a8b06fab
also
You did not have a value prop on the input field, thus you wont be able to reset the field after submit is executed.
<input
className="board-add"
onSubmit={this.onHandleSubmit}
onChange={this.onHandleChange}
type="search"
name="textarea"
value={this.state.input}
placeholder="How shall we call the board?"
/>
codesandbox
https://codesandbox.io/s/adoring-elbakyan-69hth?file=/src/App.js:0-1459
Hope this answers your question.
AddForm.js
import React from "react";
import "./styles.css";
import TaskBoard from "./Taskboard";
export default class Addform extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
arr: []
};
this.onHandleChange = this.onHandleChange.bind(this);
this.onHandleSubmit = this.onHandleSubmit.bind(this);
}
onHandleChange(e) {
this.setState({
input: e.target.value
});
}
onHandleSubmit(e) {
e.preventDefault();
this.setState({
arr: [...this.state.arr, this.state.input],
input: ""
});
}
render() {
console.log(this.state.arr);
return (
<div className="adder">
<h1 className="header">Enter the type of tasks you need to be done:</h1>
<div>
<form>
<input
className="board-add"
onSubmit={this.onHandleSubmit}
onChange={this.onHandleChange}
type="search"
name="textarea"
value={this.state.input}
placeholder="How shall we call the board?"
/>
<p>
<button className="cancel">CANCEL</button>
<button onClick={this.onHandleSubmit} className="create">
CREATE
</button>
</p>
</form>
</div>
{this.state.arr.map(item => (
<TaskBoard taskType={item} />
))}
</div>
);
}
}
Taskboard.js
import React from "react";
export default function TaskBoard(props) {
return <div style={{ color: "tomato" }}> {props.taskType}</div>;
}
I made an HTTP call in react using Axios. It works perfectly fine. But when I try to open a bootstrap 4 modal after HTTP call success. It shows me an error 'modal is not a function'. I try a number of ways to solve this but unable to solve the problem. I didn't upload the whole code as it is quite long. Let me know in the comments if you want any additional code sample. Please help.
import $ from 'jquery';
import '../assets/css/signup.css';
import { Link } from 'react-router-dom';
import axios from 'axios';
import SuccessMessage from './dashboard/SuccessMessage';
class SignUp extends React.Component{
constructor()
{
super()
this.state={
firstName:'',
lastName:'',
email:'',
phoneNumber:'',
password:'',
confirmPassword:'',
isSignUp:false
}
}
componentDidUpdate()
{
if(this.state.isSignUp === true)
{
let user = {
firstName: this.state.firstName,
lastName: this.state.lastName,
email:this.state.email,
phoneNumber:this.state.phoneNumber,
password:this.state.password
}
console.log(user);
var first_name = user.firstName;
var last_name=user.lastName;
var email=user.email;
var phone_no=user.phoneNumber;
var password = user.password;
axios.post("http://ec2-14-2a9-69-0b6.us-west-2.compute.amazonaws.com:4000/dashboard/register", {
first_name,
last_name,
email,
phone_no,
password
}, {
headers: header
})
.then(res => {
console.log(res);
if(res.status === 200 && res.data.success === true)
{
setTimeout(() =>
{
$('#signup-success').modal('show');
},200)
}
})
}
}
handleSubmit=(e) =>
{
e.preventDefault();
this.setState({isSignUp:true});
}
render()
{
return(
<SuccessMessage heading="Sign Up Successfully!" description="Please login in to access your account" iconClass="fa fa-check bg-golden flex all-center border-radius-50" modalId="signup-success"/>
)
}
Success Message component
<div className="modal" id={this.props.modalId}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h4 className="modal-title">Modal Heading</h4>
<button type="button" className="close" data-dismiss="modal">×</button>
</div>
<div className="modal-body align-center" style={style}>
<i style={icon} className={this.props.iconClass} ></i>
<h3 className="heading color-black">{this.props.heading}</h3>
<p className="paragraph color-black">{this.props.description}</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
Try not to use jquery and react together. You could achieve what you are saying using the react state:
class SignUp extends React.Component{
constructor()
{
super()
this.state={
firstName:'',
lastName:'',
email:'',
phoneNumber:'',
password:'',
confirmPassword:'',
isSignUp:false,
showModal: false
}
}
componentDidUpdate()
{
if(this.state.isSignUp === true)
{
let user = {
firstName: this.state.firstName,
lastName: this.state.lastName,
email:this.state.email,
phoneNumber:this.state.phoneNumber,
password:this.state.password
}
console.log(user);
var first_name = user.firstName;
var last_name=user.lastName;
var email=user.email;
var phone_no=user.phoneNumber;
var password = user.password;
axios.post("http://ec2-14-2a9-69-0b6.us-west-2.compute.amazonaws.com:4000/dashboard/register", {
first_name,
last_name,
email,
phone_no,
password
}, {
headers: header
})
.then(res => {
console.log(res);
if(res.status === 200 && res.data.success === true)
{
setTimeout(() =>
{
this.setState({ showModal: true });
},200)
}
})
}
}
handleSubmit=(e) =>
{
e.preventDefault();
this.setState({isSignUp:true});
}
render()
{
return(
<div>
{
this.state.showModal &&
<SuccessMessage heading="Sign Up Successfully!" description="Please login in to access your account" iconClass="fa fa-check bg-golden flex all-center border-radius-50" modalId="signup-success"/>
</div>
)
}
Also, I guess you got a display: none or something in the modal as you are doing a .show using jquery. Put that to display always as it will be only shown if the state is true.
Actually getting the Bootstrap Modal to display using React (without jQuery) requires DOM manipulation. Bootstrap 4 uses jQuery to add a modal backdrop element, adds the modal-open class to the body, and finally adds display:block to the .modal wrapper.
This is why it's preferable to using reactstrap, react-bootstrap, etc... since they've already componentized the Bootstrap Modal.
If you must show (toggle) the Bootstrap Modal in React without jQuery (or other component framework), here's an example:
class SuccessMessage extends React.Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
modalClasses: ['modal','fade']
}
}
toggle() {
document.body.className += ' modal-open'
let modalClasses = this.state.modalClasses
if (modalClasses.indexOf('show') > -1) {
modalClasses.pop()
//hide backdrop
let backdrop = document.querySelector('.modal-backdrop')
document.body.removeChild(backdrop)
}
else {
modalClasses.push('show')
//show backdrop
let backdrop = document.createElement('div')
backdrop.classList = "modal-backdrop fade show"
document.body.appendChild(backdrop)
}
this.setState({
modalClasses
})
}
render() {
return (
<div
id="messageModal"
className={this.state.modalClasses.join(' ')}
tabIndex="-1"
role="dialog"
aria-hidden="true"
ref="messageModal"
>
<div className="modal-dialog modal-dialog-centered modal-lg">
<div className="modal-content">
<div className="modal-header">
<h4>
Success
</h4>
...
</div>
<div className="modal-body">
...
</div>
</div>
</div>
</div>
)
}
}
Working Demo: https://codeply.com/p/4EV36QjwCB
The state of the app is ok. It is updating when I change a value in the textarea I can see the changement in the state component with the react utility but the css doodle don't update. I must refresh manually to see the changes I don't understand why. Thanks a lot
class App extends Component {
state ={
dood: doodText
}
componentDidMount(){
const dood=localStorage.getItem('dood')
if(dood){
this.setState({dood})
}
else{
this.setState({dood: doodText})
}
}
componentDidUpdate(){
const {dood}= this.state
localStorage.setItem('dood', dood)
}
handleChange = event =>{
var dood= event.target.value
this.setState({dood})
}
render(){
return (
<div className="container" onChange={this.handleChange} >
<div className="row">
<div className="col-sm-6">
<textarea onChange={this.handleChange} value={this.state.dood}
className="form-control"
rows="25" />
</div>
</div>
<div className="col-sm-6" onChange={this.handleChange} >
<css-doodle >{this.state.dood}</css-doodle>
</div>
<div>
</div>
</div>
);
}
}
export default App;
Just set some order
I think its should work, I add a div with dood inside to see if its work.
And I write some comment for you.
class App extends Component {
constructor() {
super();
this.handleChange = this.handleChange.bind(this);
}
state = {
dood: doodText
}
componentDidMount() {
const dood = localStorage.getItem('dood')
if (dood) {
this.setState({ dood })
}
// THIS ELSE DO NOT NECESSARY
// else {
// this.setState({ dood: doodText })
// }
}
componentDidUpdate() {
// FOR WHY IS THAT HAPPEN EVERY UPDATE?
const dood = this.state.dood
localStorage.setItem('dood', dood)
}
// USE BIND IS BETTER
handleChange(ev) {
var dood = ev.target.value
this.setState({ dood })
}
render() {
return (
<div className="container" >
<div className="row">
<div className="col-sm-6">
<textarea onChange={this.handleChange} value={this.state.dood}
className="form-control"
rows="25" />
</div>
</div>
<div>{dood}</div>
<div className="col-sm-6" >
<css-doodle >{this.state.dood}</css-doodle>
</div>
</div>
);
}
}
export default App;
css-doodle provides an .update() method to manually update it, see:
https://css-doodle.com/#js-api-update
So you can listen to the change or input event of the textarea and then call .update()
so i'm facing an issue where whenever I write something in input, handleCommentAdded is called which calls setState, re-rendering everything. This makes everything that is typed or was typed in the input to appear as comments and i want what is in the input when I click submit to appear as comment. How can I fix this?
class WriteComments extends React.Component {
constructor(props) {
super(props);
this.state = {
commentAdded:"",
}
this.handleButton = this.handleButton.bind(this);
this.handleCommentAdded = this.handleCommentAdded.bind(this);
}
handleCommentAdded(event) {
this.setState({newComment: event.target.value});
}
handleButton() {
return(
<div>
{comment}
</div>
)
}
render() {
return(
<div>
<input type="text" value={this.state.commentAdded} onChange=
{this.handleCommentAdded}/>
<div className="button">
<button
type="button"
onClick={e => this.handleButton(e)}
>
Write
</button>
</div>
)
}
}
Error is calling handleCommentAdded on onChange
set state in handleButton
class WriteComments extends React.Component {
constructor(props) {
super(props);
this.state = {
commentAdded: ""
};
this.inputRef = React.createRef();
this.handleButton = this.handleButton.bind(this);
}
handleButton() {
this.setState({ commentAdded: this.inputRef.current.value });
}
render() {
return (
<div>
<input type="text" ref={this.inputRef} />
<div className="button">
{this.state.commentAdded !== "" ? (
<div>{this.state.commentAdded}</div>
) : (
<button type="button" onClick={e => this.handleButton(e)}>
Write
</button>
)}
</div>
</div>
);
}
}
ReactDOM.render(<WriteComments />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root' />
I created a demo where textfield value can be get by button click. Component will render everytime when setState calls. Hope it can help you!
class App extends React.Component{
state ={ inputValue:"" };
render(){
return(
<div>
<input type="text" value={this.state.inputValue} onChange={this.handleChange} />
<button onClick={this.handleSubmit}>Submit</button>
</div>
);
}
handleChange=(e)=>{
this.setState({ inputValue: e.target.value });
}
handleSubmit=()=>{
console.log("inputValue::", this.state.inputValue);
}
}
ReactDOM.render(<App/>, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I'm stuck on my note taking app. Basically the App component passes in data to the NoteEntry component through props. Yet I can't figure out how to edit the previous passed text through props within each NoteEntry instance when I click the "edit" button. The edit button is supposed to bring up text inputs to change the content by updating the text and then pressing the save button. Any tips on how to go about it?
class App extends Component {
constructor(props) {
super(props);
this.state = {
notes: [],
title: "",
details: ""
}
this.updateTitle = this.updateTitle.bind(this);
this.updateDetails = this.updateDetails.bind(this);
this.submitHandler = this.submitHandler.bind(this);
this.deleteHandler = this.deleteHandler.bind(this);
}
updateTitle(event) {
this.setState({ title: event.target.value });
}
updateDetails(event) {
this.setState({ details: event.target.value });
}
submitHandler(e) {
e.preventDefault();
if (!this.state.title.length || !this.state.details.length) {
return;
}
const newNote = {
newTitle: this.state.title,
newDetails: this.state.details
}
this.setState(prevState => ({
notes: prevState.notes.concat(newNote),
title: "",
details: ""
}))
}
deleteHandler(id) {
this.setState(prevState => ({
notes: prevState.notes.filter(el => el !== id)
}))
}
render() {
return (
<div className="container">
<h1 className="title">React Notes App</h1>
<NoteForm
titleValue={this.state.title}
detailsValue={this.state.details}
titleHandle={this.updateTitle}
detailsHandle={this.updateDetails}
onSubmit={this.submitHandler}
/>
<div className="entry-section">
{this.state.notes.map((note, i) => (
<NoteEntry
key={i}
title={note.newTitle}
details={note.newDetails}
deleteNote={this.deleteHandler.bind(this, note)}
/>
))}
</div>
</div>
);
}
}
const NoteForm = (props) => {
return (
<div>
<form className="form-section">
<input
className="title-input"
type="type"
placeholder="Title"
value={props.titleValue}
onChange={props.titleHandle}
/>
<br />
<textarea
className="details-input"
cols="20"
rows="3"
placeholder="Details"
value={props.detailsValue}
onChange={props.detailsHandle}
/>
<br />
<button
className="input-button"
onClick={props.onSubmit}
>Add Note</button>
</form>
</div>
)
}
class NoteEntry extends Component {
constructor(props) {
super(props);
this.state = {
display: false,
editTitle: this.props.title,
editDetails: this.props.details,
editing: false
}
this.displayToggle = this.displayToggle.bind(this);
this.edit = this.edit.bind(this);
this.save = this.save.bind(this);
}
displayToggle() {
this.setState(prevState => ({
display: !prevState.display
}))
}
edit() {
this.setState({
editing: true
})
}
save() {
let titleVal = this.refs.updateTitle.value;
let detailsVal = this.refs.updateDetails.value;
this.setState({
editTitle: titleVal,
editDetails: detailsVal,
editing: false
})
}
render() {
return (
<div className="entry">
<div className="entry-header" onClick={this.state.editing ? null : this.displayToggle}>
{this.state.editing ? (
<input ref="updateTitle" className="edit-title" type="text" />
) : (
<h2 className="entry-title">{this.props.title}</h2>
)}
<p className="timestamp">{this.displayTime}</p>
</div>
<hr />
<div className={"entry-content " + (!this.state.display ? "hide-details" : null)}>
{this.state.editing ? (
<textarea ref="updateDetails" className="edit-details" cols="10" rows="2"></textarea>
) : (
<p className="details">{this.props.details}</p>
)}
<div className="entry-buttons">
{this.state.editing ? (
<button className="save" onClick={this.save}>Save</button>
) : (
<button className="edit" onClick={this.edit}>Edit</button>
)
}
<button className="delete" onClick={this.props.deleteNote}>Delete</button>
</div>
</div>
</div>
)
}
}
You can do by pass data from child to parent component as mention it in comment.
In you case NoteEntry add onEditNote props. This props use for function by parent (App component) and use by onClick edit button.
<NoteEntry
...
onEditNote={this.handleClickEdit}
/>
then in class NoteEntry
<button className="edit" onClick={() => this.props.handleClickEdit(this.props.title, this.props.detail)}>Edit</button>
So, handleClickEdit handle by App component and set it to your state
handleClickEdit = (_title, _detail) => {
this.setState({title: _title, details: _detail});
}
Now, your NoteForm component able to edit.