Data only shows up when I click twice on submit on ReactJs - node.js

I'm trying to create a link shortener using Reactjs, after I set up the post request for the long URL, I need to display the resulting short URL. The problem is I can't seem to be able to do that. The resulting link only shows up when I click twice on the submit button, but if I refresh the page and click submit, the shortened link does not show up.
I'm hoping you can help me with that, here's my code:
import './App.css';
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import React, {Component} from 'react';
import axios from 'axios'
class App extends Component {
constructor(){
super()
this.changelongUrl=this.changelongUrl.bind(this)
this.onSubmit=this.onSubmit.bind(this)
this.state={
longUrl:'',
shortenedUrl :[],
urls:[]
}
}
changelongUrl(event){
this.setState({
longUrl : event.target.value
})
}
onSubmit(event){
event.preventDefault()
const registered={
longUrl: this.state.longUrl
}
axios.post('http://localhost:5000/api/url/shorten',registered)
axios.get('http://localhost:5000/')
.then(response => {
this.setState({ urls: response.data });
console.log(this.state.urls)
})
this.setState({
shortenedUrl: this.state.urls.filter(url => url.longUrl === this.state.longUrl).map(filteredUrl => (
filteredUrl.shortUrl
))
})
console.log(this.state.shortenedUrl)
this.setState({
longUrl:''
})
}
render(){
return(
<div className="App">
<header className="App-header">
<form onSubmit={this.onSubmit} style={{
display: 'flex',
flexDirection: 'column'}}>
<TextField value={this.state.longUrl} onChange={this.changelongUrl}
style={{ marginBottom: 22 }} className="textfield" id="outlined-basic"
label="Please Input Your Link" variant="outlined" />
<Button style={{
marginBottom: 22,
backgroundColor: "#47597E",
padding: "10px 20px",
fontSize: "18px"}}
variant="contained" type= 'Submit'>Shorten</Button>
</form>
<a href={this.state.shortenedUrl}>{this.state.shortenedUrl}</a>
</header>
</div>)
}
}
export default App;

Related

Using axios post response in the jsx react

I want to take the data response from the Axios post, and display it on the page:
import React, { useRef} from 'react';
import logo from './assets/img/lupa.png';
import { Form } from "#unform/web";
import Input from './components/forms/input';
import * as Yup from "yup";
import './App.css';
import axios from 'axios';
function App() {
const formRef = useRef(null);
async function handleSubmit(data, ){
try{
const schema = Yup.object().shape({
nn: Yup.number().min(8,"O campo eh obrigatorio e precisa ter 8 ou mais caracteres")
})
await schema.validate(data)
console.log(data)
}catch(err){
if(err instanceof Yup.ValidationError){
console.log(err)
}}
axios.post("http://localhost:8080/api", data).then(res => console.log(res.data))
.catch(err => console.log(err));
}
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>$ Search $</h2>
</div>
<Form ref={formRef} onSubmit={handleSubmit}>
<Input name="nn" type="number"/>
<button type='submit'>buscar</button>
</Form>
</div>
);
}
export default App;
But I don't know how to work with that res.data and how to display it on the page by the jsx react, I tried to use useState and set it in the axios.post("http://localhost:8080/api", data).then(res => setState(res.data))
.catch(err => console.log(err)); - but when I console.log someState it brings an object null, i tried to display on the page using
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>$ Search $</h2>
</div>
<Form ref={formRef} onSubmit={handleSubmit}>
<Input name="nn" type="number"/>
<button type='submit'>buscar</button>
</Form>
{
someState.length >=1 ? someState.map((some, idx) =>{
return <p key={idx}>{some.data}</p>
})
: ""
}
</div>
);
}
but nothing were display! ( If you have some suggestion to change of the overall code, you can answer too ), How can I fix this 2 problems ? I want to learn moreThe first object Im printing my input, to check if it are working, and the second object its what I recieved from the axios post response(.then(res => console.log(res.data), I want to display this object "resultado"
Object { nn: "00000000353" }
Object { ip: "200.1******", resultado: 961 }
​
ip: "200.1*****"
​
resultado: 961
​
<prototype>: Object { … }
See this nice post by digitalOcean How to use axios in ReactJs
https://www.digitalocean.com/community/tutorials/react-axios-react
Hope you got a lot of help from this post.

How to make GridList face vertically in One Row with React and materialUI on Mobile

How do I make Materia-UI GridList Face vertically in One Row on Mobile?
My GridList is two in a row which is what I wanted but when I inspect it on mobile it still shows two in a row instead of One. that means it's not responsive, How do I make it responsive?
this is my Events Component.
import React from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import GridList from "#material-ui/core/GridList";
import GridListTile from "#material-ui/core/GridListTile";
import GridListTileBar from "#material-ui/core/GridListTileBar";
import ListSubheader from "#material-ui/core/ListSubheader";
mport IconButton from "#material-ui/core/IconButton";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
import Typography from "#material-ui/core/Typography";
const useStyles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 1000,
height: 950,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
});
class EventsList extends React.Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<GridList cellHeight={330} className={classes.gridList} spacing={8}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.eventImage}>
<img src={tile.eventImage} alt={tile.title} />
<GridListTileBar title={tile.title} titlePosition="top" />
<GridListTileBar
paragraph={tile.description}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
export default withStyles(useStyles)(EventsList);
this is the List of my events displayed by GridList on Mobile
but something like this is what I want to see when I am on Mobile.
Since you are using class based component, you can use withWidth to conditionally set cols value to GridList.
See working example here in codesandbox
Example code snippet
class TitlebarGridList extends Component {
render() {
const { classes, width } = this.props; // <---- see here
let columns = width === "xs" || width === "sm" ? 1 : 2;
console.log("=========>", width);
return (
<div className={classes.root}>
<GridList cellHeight={200} className={classes.gridList} cols={columns}> {/* //<---- see here */}
<GridListTile key="Subheader" cols={3} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{tileData.map(tile => (
<GridListTile key={tile.title}>
<img className={classes.image} src={tile.img} alt={tile.title} />
</GridListTile>
))}
</GridList>
</div>
);
}
}
TitlebarGridList.propTypes = {
classes: PropTypes.object.isRequired
};
export default compose(
withStyles(styles, {
name: "TitlebarGridList"
}),
withWidth() //<---- see here
)(TitlebarGridList);
Note: withWidth will be deprecated sometime in the future, so consider to use useMediaQuery hook (in that case you have to switch to functional component).

How to use Material Ui on React. getting error Invalid Hook call

`×
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app`
I am new to React, my code was working fine but I decided to use MaterialUi today, now it's giving me errors, I have tried googling but I didn't succeed. Another thing is that my this.state.events is returning an Empty array, instead of a list of events. How do I fix this?
My React-dom version is ─ react-dom#16.13.1 and React version is ─ react#16.13.1
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
import { makeStyles } from "#material-ui/core/styles";
import GridList from "#material-ui/core/GridList";
import GridListTile from "#material-ui/core/GridListTile";
import GridListTileBar from "#material-ui/core/GridListTileBar";
import ListSubheader from "#material-ui/core/ListSubheader";
import IconButton from "#material-ui/core/IconButton";
export default class EventsList extends Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
}));
const classes = useStyles();
return (
<div className={classes.root}>
<GridList cellHeight={180} className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.author}</span>}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
makeStyles returns a hook i.e. useStyles. You can only use hooks in functional components.
One option is to convert your class component to functional. Also make sure to put makeStyles code outside of component(you don't want to execute it on every re-render)
import React, { useEffect, useState } from "react";
// other imports
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
}));
const EventsList = () => {
const [events, setEvents] = useState([]);
const classes = useStyles();
useEffect(() => {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}, []);
return (
<div className={classes.root}>
// rest of code...
</div>
);
};
Another option is to keep class based component intact and use withStyles.
See withStyles API doc:
Use the function signature if you need to have access to the theme. It's provided as the first argument.
import { withStyles } from "#material-ui/core";
const styles = (theme) => ({
root: {
display: "flex",
flexWrap: "wrap",
justifyContent: "space-around",
overflow: "hidden",
backgroundColor: theme.palette.background.paper,
},
gridList: {
width: 500,
height: 450,
},
icon: {
color: "rgba(255, 255, 255, 0.54)",
},
});
class EventsList extends Component {
constructor(props) {
super(props);
this.state = { events: [] };
}
componentDidMount() {
axios
.get("http://localhost:9000/events/")
.then((response) => {
this.setState({ events: response.data });
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div className={classes.root}>
<GridList cellHeight={180} className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: "auto" }}>
<ListSubheader component="div">December</ListSubheader>
</GridListTile>
{this.state.events.map((tile) => (
<GridListTile key={tile.img}>
<img src={tile.img} alt={tile.title} />
<GridListTileBar
title={tile.title}
subtitle={<span>by: {tile.author}</span>}
actionIcon={
<IconButton
aria-label={`info about ${tile.title}`}
className={classes.icon}
></IconButton>
}
/>
</GridListTile>
))}
</GridList>
</div>
);
}
}
export default withStyles(styles)(EventsList);
Well, it is pretty much what the error says. Hooks can be used only with functional components. EventsList is a class component and you are trying to use makeStyles in it.
I faced the same issue, but I noticed that terminal was showing a "compiled successfully" message, and still the browser gave me this error.
I actually installed the material-ui/icons as: sudo npm install -g #material-ui/icons
( I thought I'll install it globally as an administrator so I will not have to install material-ui, every time on different projects/react apps)
Inside the react app I was working, I just ran ( npm install #material-ui/icons ) which updated the node_modules folder inside my react app, and the error was gone and everything was working fine on the browser as well.
Solution: just run "npm install #material-ui/core" and "npm install #material-ui/icons" on the terminal, being in the react app directory your'e working in. Hopefully, everything will get fixed.

Pass a valid time type usnig moment from React setState to postgres

I am new in coding and essentially in React. I am trying to create a human resource management system that will have an employee and an admin. I am now working on using an axios to post to knex postgres as db and nodejs.
I need help to pass in a correct value with format of "HH:mm:ss" to my backend taking time type.
This is my knex migration:
exports.up = function(knex) {
return knex.schema.createTable('undertime_overtime', (table) => {
table.increments('id').primary();
table.date('date_filed').notNullable(); //has to be default date now?
table.time('from_time').notNullable();
table.time('to_time').notNullable();
table.string('reason').notNullable();
table.integer('time_type').defaultTo(1);
table.boolean('isDeleted').defaultTo(0);
table.boolean('isAccepted').defaultTo(0);
table.timestamp('created_at').defaultTo(knex.fn.now());
table.timestamp('modified_at').defaultTo(null);
table.integer('created_by').unsigned().notNullable();
table.foreign('created_by').references('employees.id');
});
Here are the things I tried that did not work:
state = {
date_filed: new Date(),
from_time: moment().format("HH:mm:ss").toString(),
to_time: moment().format("HH:mm:ss"),
reason: '',
time_type: 1,
created_by: 1 //todo
};
handleFromTime = time => {
this.setState({
from_time: time.format("HH:mm:ss")
});
console.log(time("HH:mm:ss"));
};
Here is my component:
import React, { Component } from 'react';
import moment from 'moment';
import { Content, Row, Col, Box, Button } from 'adminlte-2-react';
import TimePicker from 'rc-time-picker';
import DatePicker from "react-datepicker";
import axios from 'axios'
import 'rc-time-picker/assets/index.css';
class OvertimeComponent extends Component {
state = {
date_filed: new Date(),
from_time: moment(),
to_time: moment(),
reason: '',
time_type: 1,
created_by: 1 //todo
};
handleChangeDateFiled = date => {
this.setState({
date_filed: date
});
console.log(date)
};
handleFromTime = time => {
this.setState({
from_time: time
});
console.log(time);
};
handleToTime = time => {
this.setState({
to_time: time
});
console.log(time.format('HH:mm:ss'));
};
handleReason = event => {
this.setState({
reason: event.target.value
})
console.log(event.target.value);
}
handleSubmit = event => {
console.log(`date-> ${this.state.date_filed} from ${this.state.from_time} to ${this.state.to_time} reason ${this.state.reason}`)
event.preventDefault()
axios.post('http://localhost:8080/api/time',this.state)
.then(response=> {
console.log(response);
}).catch(error => {
console.error(error);
})
}
footer = [
<Button key="btnSubmit" type="success" pullRight text="Submit" onClick={this.handleSubmit} />,
];
render() {
return (
<Content title="Overtime" subTitle="Requests" browserTitle="Overtime">
<Row>
<Col md={6}>
<Row>
<Col xs={12}>
<Box title="Overtime Application" type="primary" collapsable footer={this.footer}>
<div className="form-group">
<label>Date</label>
<div>
<DatePicker name="date_filed" selected={this.state.date_filed} onChange={this.handleChangeDateFiled}/>
</div>
</div>
<div className="form-group">
<label>From</label>
<div>
<TimePicker name="from_time" value={this.state.from_time} onChange={this.handleFromTime} />
</div>
</div>
<div className="form-group">
<label>To</label>
<div>
<TimePicker name="to_time" value={this.state.to_time} onChange={this.handleToTime} />
</div>
</div>
<div className="form-group">
<label>Reason</label>
<textarea type="text" name="reason" value={this.state.reason} onChange={this.handleReason} className="form-control" placeholder="Enter ..." />
</div>
</Box>
</Col>
</Row>
</Col>
<Col md={6}>
<Box title="Request Status" type="primary" collapsable>
<div className="form-group">
<label>todo</label>
</div>
</Box>
</Col>
</Row>
</Content>);
}
}
export default OvertimeComponent;
I found the issue. I should've touched the axios post to get the format I wanted from the moment object.
axios.post('http://localhost:8080/api/time',{
'date_filed':this.state.date_filed,
'from_time':this.state.from_time.format('HH:mm:ss'),
'to_time':this.state.to_time.format('HH:mm:ss'),
'reason':this.state.reason,
'created_by': 1 //todo
})

Importing Express while trying to connect front-end(React) and back-end(Node.js)

I'm really new to js and I'm trying to build a full-stack web app. I've built most of the front-end React code and my back-end file has the connection and query to the db.
I'm trying to connect both of those files together, but as soon as i try to import 'express' in any of the files, it breaks. Without importing express it works alright.
Giving me this error on the browser when it runs: "TypeError: Unable to get property 'prototype' of undefined or null reference"
Index.js (trying to import Express here)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// import './index.css';
// var express = require('express')
// var app = express()
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
// const axios = require('axios')
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers:
serviceWorker.unregister();
App.js (front-end)
import React from 'react';
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
import Box from '#material-ui/core/Box';
import { createMuiTheme } from '#material-ui/core/styles';
import { ThemeProvider } from '#material-ui/styles';
import { Typography } from '#material-ui/core';
// var express = require('express')
// var app = express()
//change the primary colours of the UI
const theme = createMuiTheme({
palette: {
primary: {
main: '#00a843',
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
},
},
});
export default class App extends React.Component
{
constructor(props) {
super(props);
this.handleEnterClick = this.handleEnterClick.bind(this);
this.handleSaveClick = this.handleSaveClick.bind(this);
this.state = {showAll: false, inputEmail: "", successfullySaved: true, newList: ""};
}
async handleEnterClick() {
//send the entered email to the server
// var xhr = new XMLHttpRequest()
// get a callback when the server responds
// xhr.addEventListener('load', () => {
// update the state of the component with the result here
// console.log(xhr.responseText)
// })
// open the request with the verb and the url
// xhr.open('PUT', '/api/controllers/AppController/enter')
// send the request
// xhr.send(JSON.stringify({ yourEmail: this.state.inputEmail }))
/*
const response = await fetch('/api/controllers/AppController/enter', {
method: 'PUT',
body: JSON.stringify({ email: this.state.inputEmail }),
})
console.log(await response.json())
*/
//update the UI to reflect the button being pressed
this.setState({showAll: true});
}
handleSaveClick() {
//save to the datbase
var xhr = new XMLHttpRequest()
// get a callback when the server responds
xhr.addEventListener('load', () => {
// update the state of the component with the result here
console.log(xhr.responseText)
})
// open the request with the verb and the url
xhr.open('PUT', '/api/controllers/AppController/save')
// send the request
xhr.send(JSON.stringify({ newList: this.state.newList }))
//update the UI to reflect the save
this.setState({showAll: false, inputEmail: "", successfullySaved: true, newList: ""});
//add a successful save message
}
render () {
return (
<form display="flex" noValidate autoComplete="off">
<ThemeProvider theme={theme}>
<div align = 'center'>
<TextField
id="tfInputEmail"
value={this.state.inputEmail}
onKeyPress={(ev) => {
if (ev.key === 'Enter') {
this.setState({showAll: true});
ev.preventDefault();
}
}}
onChange={e => this.setState({ inputEmail: e.target.value })}
style={{ width: 600}}
placeholder="first_last"
autoComplete = "email"
InputLabelProps={{
shrink: true,
style: {fontSize: 17, fontFamily: "Helvetica"}
}}
inputProps={{
style: {fontFamily: "Helvetica"}
}}
variant="outlined"
/>
<br/>
<Button id="btnEnter" variant="contained" color="primary"
style={{ marginTop: 15, marginBottom: 35, width: 600, height: 35}} onClick={this.handleEnterClick}>
Enter
</Button>
<PressedEnter show={this.state.showAll} click={this.handleSaveClick} list={this.state.newList}/>
</div>
</ThemeProvider>
</form>
);
}
}
function PressedEnter(props)
{
if(!props.show) {
return null;
}
return (
<div >
<Box fontSize={18} fontFamily="Helvetica" marginLeft="9px"
marginBottom="20px" marginTop="30px">
Check spelling and formatting before clicking 'Update your list' below. There's no error checking at the moment.
</Box>
<div width="100%" horizontal layout >
{
// REPLACE THE ABOVE DIV WITH A GRID LAYOUT FROM MATERIAL UI
}
{// Vertical layout for the textbox and its label
}
<div>
<Box fontSize={16} fontFamily="Helvetica"
marginBottom="10px" marginTop="20px">
Add/change/delete emails and separate by semicolon (;) here:
</Box>
<TextField
id="tfChangeList"
multiline
style={{ margin: 8, width: 446}}
InputLabelProps={{
shrink: true,
style: {fontSize: 20, fontFamily: "Helvetica"}
}}
inputProps={{
style: {height:300, fontFamily: "Helvetica"}
}}
variant="outlined"
/>
</div>
{// Vertical layout for the textbox and its label
}
<div>
<Box fontSize={16} fontFamily="Helvetica"
marginBottom="10px" marginTop="20px">
View your current Pulse Check list here:
</Box>
<TextField
disabled
id="tfCurrentList"
multiline
style={{ margin: 8, width: 446}}
InputLabelProps={{
shrink: true,
style: {fontSize: 20, fontFamily: "Helvetica"}
}}
inputProps={{
style: {height:300, fontFamily: "Helvetica"}
}}
variant="outlined"
/>
</div>
</div>
<br/>
<Button id="btnSave" variant="contained" color="primary" style={{ marginLeft: 8, marginBottom: 8,
marginTop: -8}} onClick={props.click}>
Save your Updates!
</Button>
</div>
);
}
);
}
Your full-stack web app should run both the client and server individually - i.e. run your Express application on localhost:3000 (the back end) and send HTTP requests to it from your client (React) running in a separate webpack server (the front end).
Because an application is "full-stack", this doesn't mean that the front and back ends are combined. These are separate. Hope this helps.

Resources