Constructor is called twice in React component - javascript

I am trying to use this component that I found in a medium article. I am creating a chatroom. The component below is the chatbox that I am trying to modify and reuse. For some reason the constructor is being called twice. I am new to react. I guessed it does this because of the state change.
import React from "react";
import io from "socket.io-client";
class Chat extends React.Component{
constructor(props){
super(props);
console.log("constructor called");
this.state = {
username: '',
message: '',
messages: []
};
this.socket = io('localhost:5000');
console.log("socket created");
this.socket.on('RECEIVE_MESSAGE', function(data){
addMessage(data);
});
const addMessage = data => {
console.log(data);
this.setState({messages: [...this.state.messages, data]});
console.log(this.state.messages);
};
this.sendMessage = ev => {
ev.preventDefault();
this.socket.emit('SEND_MESSAGE', {
author: this.state.username,
message: this.state.message
})
this.setState({message: ''});
}
}
render(){
return (
<div className="container">
<div className="row">
<div className="col-4">
<div className="card">
<div className="card-body">
<div className="card-title">Global Chat</div>
<hr/>
<div className="messages">
{this.state.messages.map(message => {
return (
<div>{message.author}: {message.message}</div>
)
})}
</div>
</div>
<div className="card-footer">
<input type="text" placeholder="Username" value={this.state.username} onChange={ev => this.setState({username: ev.target.value})} className="form-control"/>
<br/>
<input type="text" placeholder="Message" className="form-control" value={this.state.message} onChange={ev => this.setState({message: ev.target.value})}/>
<br/>
<button onClick={this.sendMessage} className="btn btn-primary form-control">Send</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Chat;

Related

Can't figure out how to redirect to home page

I just started watching some guide on youtube how to make simple fronend in React with bootstrap. I'm stuck for hours on one step since on react-router-dom v6 I can't use history anymore and as I'm using React class comp, I don't know how to implement "useNavigate" to my code. Thing that I want to do is when I add new book to go back to home page which is "/books". Here is my code:
import React, { Component } from 'react';
import {Link} from 'react-router-dom';
import BookService from '../services/BookService';
class CreateBookComponent extends Component {
constructor(props){
super(props)
this.state={
bookName: "",
authorName: ""
}
this.changeBookNameHandler = this.changeBookNameHandler.bind(this);
this.changeAuthorNameHandler = this.changeAuthorNameHandler.bind(this);
this.saveBook = this.saveBook.bind(this);
}
changeBookNameHandler = (event) => {
this.setState({bookName: event.target.value});
}
changeAuthorNameHandler = (event) => {
this.setState({authorName: event.target.value});
}
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
**here is where did guy in guide called this.props.history.push('books');**
});
}
render() {
return (
<div>
<div className='container mt-2'>
<div className='row'>
<div className='card col-md-6 offset-md-3 offset-md-3'>
<h1 className='text-center'>Add Book</h1>
<div className='card-body'>
<form>
<div className='form-group'>
<label> Book Name</label>
<input placeholder='Book Name' name='bookName' className='form-control'
value={this.state.bookName} onChange={this.changeBookNameHandler}/>
</div>
<div className='form-group mt-2'>
<label> Author Name</label>
<input placeholder='Author Name' name='authorName' className='form-control'
value={this.state.authorName} onChange={this.changeAuthorNameHandler}/>
</div>
<button className='btn btn-success mt-2' onClick={this.saveBook}>Save</button>
<Link to="/books" className="btn btn-danger mt-2" style={{marginLeft: '10px'}}>Cancel</Link>
</form>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default CreateBookComponent;
You can try this:
saveBook = (e) => {
e.preventDefault();
let book = {bookName: this.state.bookName, authorName: this.state.authorName};
console.log('book => ' + JSON.stringify(book));
BookService.createBook(book).then(res => {
window.location.href = "youWebsiteUrl" + "/books"
});
}

innerHTML works only once in my react app

What I am trying to do is clear my container div when the user hits the search button so all the existing search results are removed.
The problem is I am using innerHTML to clear the container div but it only works for the first time.
If you search for something for the second time then you will see no results are rendered.
I've just started learning reactjs.
Here is my code (I have removed the API key and the id just FYI).
import React from "react";
import Recipe from "./Recipe";
import "./styles.css";
export default class App extends React.Component {
constructor() {
super();
this.state = {
searchQuery: "Icecream",
searchData: [],
error: false,
loader: false
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
[e.target.name]: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
document.querySelector(".control.field").classList.add("is-loading");
this.setState({
error: false,
loader: true
});
document.querySelector(".columns").innerHTML = "test";
fetch(
`https://api.edamam.com/search?q=${
this.state.searchQuery
}&app_id=id&app_key=key`
)
.then(response => response.json())
.then(data => {
this.setState({
searchData: data.hits
});
})
.catch(err => {
this.setState({
error: true
});
})
.finally(() => {
document.querySelector(".control.field").classList.remove("is-loading");
this.setState({
loader: false
});
});
}
renderIngredients = arr => arr.map((el, index) => <li key={index}>{el}</li>);
render() {
let result;
result = this.state.searchData.map((el, index) => (
<Recipe
key={index}
image={el.recipe.image}
title={el.recipe.label}
ingredients={this.renderIngredients(el.recipe.ingredientLines)}
/>
));
return (
<div>
<form className="px-3 py-3" onSubmit={this.handleSubmit}>
<div className="field is-grouped">
<p className="control field is-expanded">
<input
className="input is-rounded"
type="text"
placeholder="Find a recipe"
name="searchQuery"
value={this.state.searchQuery}
onChange={this.handleChange}
/>
</p>
<p className="control">
<button className="button is-primary">Search</button>
</p>
</div>
</form>
{this.state.loader ? (
<div className="spinner-box">
<div className="three-quarter-spinner" />
</div>
) : (
""
)}
{this.state.error ? (
<div className="px-3 py-3">
<div className="notification is-danger">
Some error occured. Unable to fetch
</div>
</div>
) : (
<div className="columns is-multiline px-3 py-3 is-mobile">
{result}
</div>
)}
</div>
);
}
}
Recipe component :
import React from "react";
export default class Recipe extends React.Component {
render() {
return (
<div className="column is-one-quarter-desktop is-half-mobile">
<div className="card">
<div className="card-image">
<figure className="image is-4by3">
<img src={this.props.image} alt="" />
</figure>
</div>
<div className="card-content">
<p className="title is-6">{this.props.title}</p>
<ul>{this.props.ingredients}</ul>
</div>
</div>
</div>
);
}
}
What do you think about using new state for that?
What I mean is that:
this.state = {
...,
focusSearch: false
}
const handleFocus = () => {
this.setState({ ...this.state, focusSearch: true});
}
<input
className="input is-rounded"
type="text"
placeholder="Find a recipe"
name="searchQuery"
value={this.state.searchQuery}
onFocus={this.handleFocus}
onChange={this.handleChange}
/>
render() {
return (
{
focusSearch ? <div></div> : <></>;
}
)
}
I figured it out this morning. It can be done easily using conditional rending and ternary operator.
Thank you, everyone.

this.props.onAdd is not a function?

I try to nest a component with a form to add records to the database, within a component that lists everything, but pressing submit gives me this error: "Uncaught TypeError: this.props.onAdd is not a function."
I have reviewed everything from top to bottom, but I don't see the problem, since it is A method that I used before without problems, but i'm new at this, so...
I'm using Laravel in the backend (in case you need to know).
Can somebody help me please?
thanks for your time!!
This is my father component:
import React, { Component } from 'react';
import Empresa from './Empresa';
import CrearEmpresa from './CrearEmpresa';
export default class Empresas extends Component {
constructor() {
super();
this.state = {
empresas: [],
empresaActual: null
}
this.handleAddEmpresa = this.handleAddEmpresa.bind(this);
}
componentDidMount() {
fetch('/api/empresas')
.then(response => {
return response.json();
})
.then(empresas => {
this.setState({ empresas });
});
}
renderEmpresas() {
return this.state.empresas.map(empresa => {
return (
<div className="card" key={empresa.id}>
<div className="card-body">
<h5 className="card-title">{empresa.nombre}</h5>
<p className="card-text">{empresa.cif} </p>
<p className="card-text">{empresa.direccion} </p>
<p className="card-text"> {empresa.telefono} </p>
<p className="card-text"> {empresa.mail}</p>
<p className="card-text"> {empresa.entradas}</p>
</div>
<div className="card-footer">
<a onClick={()=>this.handleClick(empresa)} >Más</a>
</div>
</div>
);
})
}
handleClick(empresa) {
this.setState({empresaActual:empresa});
}
handleAddEmpresa (empresa) {
empresa.entradas = Number(empresa.entradas);
fetch( 'api/empresas/', {
method:'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(empresa)
})
.then(response => {
return response.json();
})
.then(data => {
this.setState((prevState)=> ({
empresas: prevState.empresas.concat(data),
empresaActual : data
}))
})
}
render() {
return (
<div className="container" id="empresas" >
<div className="row">
<div className="col s12 offset-m l8">
<h3> Empresas </h3>
{ this.renderEmpresas() }
</div>
<Empresa empresa={this.state.empresaActual} />
</div>
<div>
<CrearEmpresa onAdd={this.handleAddEmpresa} />
</div>
</div>
);
}
}
```````````````````````````````````````````````````````````````````````````````````````````````````
And this is the child:
```````````````````````````````````````````````````````````````````````````````````````````````````
import React, {Component} from 'react';
export default class CrearEmpresa extends Component {
constructor(props) {
super(props);
this.state = {
nuevaEmpresa: {
nombre: '',
direccion: '',
telefono: '',
mail: '',
entradas: 0
}
}
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange (e){
this.setState ({
[e.target.id]: e.target.value
})
}
handleSubmit(e) {
e.preventDefault();
console.log(this.state);
this.props.onAdd(this.state.nuevaEmpresa);
}
render() {
return(
<div>
<div className="container">
<form onSubmit={this.handleSubmit} className="transparent">
<h5 className="grey-text text-darken-3">Nueva Empresa</h5>
<div className="input-field">
<label htmlFor="nombre">Nombre</label>
<input type="text" name="nombre" id="nombre" onChange={this.handleChange} />
</div>
<div className="input-field">
<label htmlFor="direccion">Dirección</label>
<textarea className="materialize-textarea" name="direccion" id="direccion"
onChange={this.handleChange}></textarea>
</div>
<div className="input-field">
<label htmlFor="telefono">Teléfono</label>
<br />
<input type="tel" name="telefono" id="telefono" onChange={this.handleChange} />
</div>
<div className="input-field">
<label htmlFor="mail">Mail</label>
<br />
<input type="email" name="mail" id="mail" onChange={this.handleChange} />
</div>
<div className="input-field">
<label htmlFor="entradas">Número de entradas</label>
<input type="number" name="entradas" id="entradas" min="10" max="50000" step="5"
onChange={this.handleChange} />
</div>
<input type="submit" value="submit" />
</form>
</div>
</div>
)
}
}
``````````````````````````````````````````````````````````````````````````````````````````````

How to call Promise.all in a handler function in React.js

I have two API calls that I am trying to make based on the input;
api.js
import axios from 'axios';
export const getWeather = input => {
};
export const getForecast = input => {
};
And in my React component:
import React, { Component } from 'react';
import WeatherDisplay from './WeatherDisplay';
import * as api from '../utils/api';
import dataTracker from '../utils/dataTracker';
import '../scss/app.scss';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
input: '',
weatherFromInput: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
console.dir(dataTracker);
}
handleChange(event) {
this.setState({
input: event.target.value,
});
}
// prettier-ignore
handleSubmit(event) {
event.preventDefault();
var promises = Promise.all(api.getWeather(this.state.input), api.getForecast(this.state.input))
promises.then(function(input) {
this.setState({ weatherFromInput: input[0], input: '' });
console.log("input", input[0]);
}.bind(this));
}
render() {
return (
<div className="container">
<div className="container">
<form name="weatherApp" onSubmit={this.handleSubmit}>
<h2>Open Weather App</h2>
<div className="row">
<div className="one-half column">
<label htmlFor="insertMode">Insert your location</label>
<input
name="zipcode"
className="u-full-width"
placeholder="please enter city or zipcode"
type="text"
autoComplete="off"
value={this.state.input}
onChange={this.handleChange}
/>
</div>
<div className="one-half column">
<label htmlFor="showMin">show minimum</label>
<input type="checkbox" />
<label htmlFor="showMax">show maximum</label>
<input type="checkbox" />
<label htmlFor="showMean">show mean</label>
<input type="checkbox" />
</div>
</div>
<div className="row">
<div className="two-half column">
<input type="submit" value="Submit" />
</div>
</div>
</form>
</div>
<div className="container">
<div className="row">
<div className="twelve columns">
{this.state.weatherFromInput !== null ? <WeatherDisplay weather={this.state.weatherFromInput} /> : null}
</div>
</div>
</div>
</div>
);
}
}
I get this error:
App.js:77 Uncaught (in promise) TypeError: undefined is not a function
Any help will be appreciated!
I believe Promise.all() needs an array, so:
var promises = Promise.all(api.getWeather(this.state.input), api.getForecast(this.state.input))
should be
var promises = Promise.all([api.getWeather(this.state.input), api.getForecast(this.state.input)])

where to put my header and footer tags in reactjs

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { login } from '../../redux/reducer';
import './LoginForm.css';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {};
this.onSubmit = this.onSubmit.bind(this);
}
render() {
let {username, password} = this.state;
let {isLoginPending, isLoginSuccess, loginError} = this.props;
return (
<header>
<h1>Company Login</h1>
</header>
<form name="loginForm" onSubmit={this.onSubmit}>
<div className="form-group-collection">
<div className="form-group">
<label>Username/User ID:</label>
<input name="username" onChange={e => this.setState({username: e.target.value})} value={username}/>
</div>
<div className="form-group">
<label>Password:</label>
<input type="password" name="password" onChange={e => this.setState({password: e.target.value})} value={password}/>
</div>
</div>
<br/>
<input type="submit" value="Login" />
</form>
<footer>Copyright © multihands.com. </footer>
)
}
onSubmit(e) {
e.preventDefault();
let { username, password } = this.state;
this.props.login(username, password);
this.setState({
username: '',
password: ''
});
}
}
const mapStateToProps = (state) => {
return {
isLoginPending: state.isLoginPending,
isLoginSuccess: state.isLoginSuccess,
loginError: state.loginError
};
}
const mapDispatchToProps = (dispatch) => {
return {
login: (username, password) => dispatch(login(username, password))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
This is my login page i want to add header in my page.. I added it already as shown in the code...But unfortunetly error occurs after running.. Where does I put my header and footer tag in my code.. If we put it in form the code runs..But the css applied to the form is affected by adding the footer and header.. So I need the correct way to place header and footer without intrude my form..
Issue is that return statement must contain a single element only and your code contains three. So basically this should work:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { login } from '../../redux/reducer';
import './LoginForm.css';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {};
this.onSubmit = this.onSubmit.bind(this);
}
render() {
let { username, password } = this.state;
let { isLoginPending, isLoginSuccess, loginError } = this.props;
return (
<div>
<header>
<h1>Company Login</h1>
</header>
<form name="loginForm" onSubmit={this.onSubmit}>
<div className="form-group-collection">
<div className="form-group">
<label>Username/User ID:</label>
<input name="username" onChange={e => this.setState({ username: e.target.value })} value={username} />
</div>
<div className="form-group">
<label>Password:</label>
<input type="password" name="password" onChange={e => this.setState({ password: e.target.value })} value={password} />
</div>
</div>
<br />
<input type="submit" value="Login" />
</form>
<footer>Copyright © multihands.com. </footer>
</div>
)
}
onSubmit(e) {
e.preventDefault();
let { username, password } = this.state;
this.props.login(username, password);
this.setState({
username: '',
password: ''
});
}
}
const mapStateToProps = (state) => {
return {
isLoginPending: state.isLoginPending,
isLoginSuccess: state.isLoginSuccess,
loginError: state.loginError
};
}
const mapDispatchToProps = (dispatch) => {
return {
login: (username, password) => dispatch(login(username, password))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
You need a wrapper inside your render function this solution should reolve your issue:-
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { login } from '../../redux/reducer';
import './LoginForm.css';
class LoginForm extends Component {
constructor(props) {
super(props);
this.state = {};
this.onSubmit = this.onSubmit.bind(this);
}
render() {
let { username, password } = this.state;
let { isLoginPending, isLoginSuccess, loginError } = this.props;
return (
<div className="wrapper">
<header>
<h1>Company Login</h1>
</header>
<form name="loginForm" onSubmit={this.onSubmit}>
<div className="form-group-collection">
<div className="form-group">
<label>Username/User ID:</label>
<input name="username" onChange={e => this.setState({ username: e.target.value })} value={username} />
</div>
<div className="form-group">
<label>Password:</label>
<input type="password" name="password" onChange={e => this.setState({ password: e.target.value })} value={password} />
</div>
</div>
<br />
<input type="submit" value="Login" />
</form>
<footer>Copyright © multihands.com. </footer>
</div>
);
onSubmit(e) {
e.preventDefault();
let { username, password } = this.state;
this.props.login(username, password);
this.setState({
username: '',
password: ''
});
}
}
}
const mapStateToProps = (state) => {
return {
isLoginPending: state.isLoginPending,
isLoginSuccess: state.isLoginSuccess,
loginError: state.loginError
};
}
const mapDispatchToProps = (dispatch) => {
return {
login: (username, password) => dispatch(login(username, password))
};
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginForm);
If you don't need the wrapper div you can use the Fragments(https://reactjs.org/docs/fragments.html) if using React Fiber.
<React.Fragment>
<header>
<h1>Company Login</h1>
</header>
<form name="loginForm" onSubmit={this.onSubmit}>
<div className="form-group-collection">
<div className="form-group">
<label>Username/User ID:</label>
<input name="username" onChange={e => this.setState({ username: e.target.value })} value={username} />
</div>
<div className="form-group">
<label>Password:</label>
<input type="password" name="password" onChange={e => this.setState({ password: e.target.value })} value={password} />
</div>
</div>
<br />
<input type="submit" value="Login" />
</form>
<footer>Copyright © multihands.com. </footer>
</React.Fragment>

Categories

Resources