Request received always is empty - javascript

I'm working with react, redux-form and laravel.
I have created a form to be able to insert notes in the database but when I show the Request in laravel an empty array always appears.
I do not know what I'm doing wrong.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
notes: [],
};
this.submitToServer = this.submitToServer.bind(this)
this.submit = this.submit.bind(this)
}
componentWillMount() {
fetch('http://127.0.0.1:8000/notes')
.then(res => res.json())
.then(json => json.results)
.then(notes => this.setState({ notes }))
.catch(console.log)
}
async submitToServer(data) {
let response = await fetch('http://127.0.0.1:8000/notes', {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-type': 'application/json',
},
body: JSON.stringify(data)
})
let responseJSON = await response.json()
return responseJSON
}
submit({ title, content }) {
this.submitToServer({ title, content })
.then(res => this.setState(prevState => ({
notes: [...prevState.notes, {
id: prevState.notes.pop().id + 1,
title: title,
content: content
}]
})))
}
render() {
if (this.state.notes.length > 0) {
return (
<div>
<h1>Notas</h1>
<Paper>
<form onSubmit={this.props.handleSubmit(this.submit)}>
<Field name="title" label="Title" component={renderField} type="text" />
<Field name="content" label='Content' component={renderField} type="text" />
<button type="submit">Submit</button>
</form>
</Paper>
))}
</div>
)
} else {
return <p>Cargando notas...</p>
}
}
}
In laravel at the moment I'm just returning the Request to show what it contains.
public function storeNote(Request $request) {
return $request;
}

Related

how to save old value to a PUT when I PUT a single value ReactJS/NodeJs

I would like to explain my problem of the day.
I map a database, then I display the result in a card
I get several results
So problem and the next one, when I modify a result, it empties all my other values, while I would like to keep the other values ​​of the other fields.
How can I fix this issue?thx all
make room for the code :)
class Chat extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
onChangegame(e) {
this.setState({ game: e.target.value })
}
onChangename(e) {
this.setState({ name: e.target.value })
}
putname = (e, chat) => {
e.preventDefault();
const config = {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: chat.id, name: this.state.name, game: this.state.game, }),
};
const url = "http://localhost:4242/api/putname";
fetch(url, config)
.then(res => res.json())
.then(res => {
if (res.error) {
alert(res.error);
} else {
alert(`ajouté avec l'ID ${res}!`);
}
}).catch(e => {
console.error(e);
}).finally(() => this.setState({ redirect: true }));
}
render() {
let datas = this.state.data.map(chat => {
return (
<div key={chat.id}>
<form onSubmit={(e) => this.putname(e, chat)}>
<p> {chat.name} </p>
<input type="text"
id="name"
onChange={this.handleChange}
value={this.state.name}
name="name"
/>
<input type="submit" value="modifier" />
</form>
<form onSubmit={(e) => this.putname(e, chat)}>
<p> {chat.game} </p>
<input type="text"
id="game"
onChange={this.handleChange}
value={this.state.game}
name="game"
/>
<input type="submit" value="modifier" />
</form>
</div>
return (
<div>
{datas}
</div>
)
}
}
export default Chat
My Back
putname = (e, chat) => {
e.preventDefault();
const config = {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ id: chat.id, name: this.state.name, game: this.state.game }),
};
const url = "http://localhost:4242/api/putname";
fetch(url, config)
.then(res => res.json())
.then(res => {
if (res.error) {
alert(res.error);
} else {
alert(`ajouté avec l'ID ${res}!`);
}
}).catch(e => {
console.error(e);
}).finally(() => this.setState({ redirect: true }));
}
The problem that I see is when you update the state you aren't preserving the previous values. For example:
instead of:
onChangegame(e) {
this.setState({ game: e.target.value })
}
onChangename(e) {
this.setState({ name: e.target.value })
}
, use:
onChangegame(e) {
this.setState({ ...this.state, game: e.target.value })
}
onChangename(e) {
this.setState({ ...this.state, name: e.target.value })
}
or even a better way it's using the same handler by destructing e.target object:
onChange(e) {
const { value, name } = e.target
this.setState({ ...this.state, [name]: [value] })
}
// ... and the in your inputs
render() {
let datas = this.state.data.map(chat => {
return (
<div key={chat.id}>
<form onSubmit={(e) => this.putname(e, chat)}>
<p> {chat.name} </p>
<input type="text"
id="name"
onChange={this.onChange}
value={this.state.name}
name="name"
/>
<input type="submit" value="modifier" />
</form>
<form onSubmit={(e) => this.putname(e, chat)}>
<p> {chat.game} </p>
<input type="text"
id="game"
onChange={this.onChange}
value={this.state.game}
name="game"
/>
<input type="submit" value="modifier" />
</form>
</div>
return (
<div>
{datas}
</div>
)

Updating a page at refresh AND change of state

I'm trying to build a todo page where I can input todos in my input field. All todos will be rendered below. I managed to build a form where I can type in a todo title and send it to my database. A small problem I'm having here is that I need to refresh the page after pushing the add button to see the new list. I assume this is because I use componentDidMount and this updates only at page refresh. Any idea how I can do this at page refresh (componentDidUpdate) AND at state change ?
FRONT-END
import React from 'react'
import './Todo.css'
import Todoitem from '../components/Todoitem'
import axios from 'axios'
import qs from "qs"
import DefaultLayout from "../layout/Default"
class Todo extends React.Component {
constructor() {
super()
this.state = {
title:"",
todos:[]
}
this.handleChange=this.handleChange.bind(this)
this.handleSubmit=this.handleSubmit.bind(this)
}
componentDidMount(){
axios({
method: "GET",
url: `${process.env.REACT_APP_API_BASE}/todo`,
withCredentials: true
})
.then(response => {
console.log(response)
let todolist = response.data;
this.setState({todos:todolist})
})
.catch(error => {
console.log("You've made an error when getting the todos charles: ",error)
})
}
handleChange(event){
event.preventDefault()
let name = event.target.name
let value = event.target.value
this.setState({
[name]:value
})
console.log(this.state.title)
}
handleSubmit(event){
event.preventDefault()
if (!this.state.title) {
debugger
}
axios({
method: "POST",
url: `${process.env.REACT_APP_API_BASE}/todo`,
data: qs.stringify({title: this.state.title}),
headers: {"content-type": "application/x-www-form-urlencoded"},
withCredentials: true
})
.then((response) => {
console.log(response)
})
.catch((error) => {
console.log(error.response)
})
}
handleDelete(todoId){
axios
.delete(`${process.env.REACT_APP_API_BASE}/todo/${todoId}`)
.then(response => {
const remainingTodos = this.state.todos.filter(element => element._id !== todoId)
this.setState({
todos: remainingTodos
})
})
.catch(err => console.log(err))
}
render() {
return (
<div>
<DefaultLayout>
<h1>To-do things for this app</h1>
<h2 className="todotitle">Add your to-do here, Charles!</h2>
<form className="todocontainer" onClick={this.handleSubmit}>
<div className="inputbuttonandfield">
<div className="inputcontainer">
<div className="captionpart">
<label className="captionlabel" htmlFor="title">Add to-do:</label><br></br>
<input className="captionform" type="text" name="title" value={this.state.title} placeholder="Type your to-do here!" onChange={(e) => this.handleChange(e)}></input>
<button className="shootbutton">Add!</button>
</div>
</div>
</div>
</form>
{
this.state.todos.map(element=> (
<div className="todosoverviewlister" key={element._id}>
<Todoitem id={element._id} title={element.title} />
<button className="tododelete" onClick={()=> this.handleDelete(element._id)}>Delete</button>
</div>
))
}
</DefaultLayout>
</div>
)
}
}
export default Todo
Todomodel
const mongoose = require("mongoose")
const Schema = mongoose.Schema
const todoSchema = new Schema({
title: String
})
const Todo = mongoose.model("todos",todoSchema)
module.exports = Todo
BACKEND
//request todos
router.get("/todo", (req,res) => {
Todo
.find()
.then(response => {
res.json(response)
})
.catch(error => {
res.json(error)
})
})
//delete todo
router.delete("/todo/:id", (req,res)=>{
Todo
.findByIdAndDelete(req.params.id)
.then(response => {
res.json(response)
})
.catch(error => {
res.json(error)
})
})
You can either update the state or sync up with database by sending another GET. Let me break it down into 2 solutions:
Just update the state
Make a GET request after the POST request and update the state
Just update the state
// you code ...
handleSubmit(event){
event.preventDefault()
const newTodo = { title: this.state.title }; // extract your todo into const
axios({
method: "POST",
url: `${process.env.REACT_APP_API_BASE}/todo`,
data: qs.stringify(newTodo), // send todo in the POST
headers: {"content-type": "application/x-www-form-urlencoded"},
withCredentials: true
})
.then((response) => {
console.log(response)
this.setState(prevState => ({ // immutably update the state
todos: [...prevState.todos, newTodo]
}));
})
.catch((error) => {
console.log(error.response)
})
}
// your code ...
Send GET after POST:
// your Todo component
class Todo extends React.Component {
constructor() {
super();
this.state = {
title: "",
todos: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
// extract method for loading TODOs (your previous componentDidMount)
loadTodos = () => {
axios({
method: "GET",
url: `${process.env.REACT_APP_API_BASE}/todo`,
withCredentials: true,
})
.then((response) => {
console.log(response);
let todolist = response.data;
this.setState({ todos: todolist });
})
.catch((error) => {
console.log(
"You've made an error when getting the todos charles: ",
error
);
});
}
componentDidMount() {
this.loadTodos(); // use the extracted method
}
handleChange(event) {
event.preventDefault();
let name = event.target.name;
let value = event.target.value;
this.setState({
[name]: value,
});
console.log(this.state.title);
}
handleSubmit(event) {
event.preventDefault();
if (!this.state.title) {
debugger;
}
axios({
method: "POST",
url: `${process.env.REACT_APP_API_BASE}/todo`,
data: qs.stringify({ title: this.state.title }),
headers: { "content-type": "application/x-www-form-urlencoded" },
withCredentials: true,
})
.then((response) => {
console.log(response);
this.loadTodos(); // use the extracted method
})
.catch((error) => {
console.log(error.response);
});
}
handleDelete(todoId) {
axios
.delete(`${process.env.REACT_APP_API_BASE}/todo/${todoId}`)
.then((response) => {
const remainingTodos = this.state.todos.filter(
(element) => element._id !== todoId
);
this.setState({
todos: remainingTodos,
});
})
.catch((err) => console.log(err));
}
render() {
return (
<div>
<DefaultLayout>
<h1>To-do things for this app</h1>
<h2 className="todotitle">Add your to-do here, Charles!</h2>
<form className="todocontainer" onClick={this.handleSubmit}>
<div className="inputbuttonandfield">
<div className="inputcontainer">
<div className="captionpart">
<label className="captionlabel" htmlFor="title">
Add to-do:
</label>
<br></br>
<input
className="captionform"
type="text"
name="title"
value={this.state.title}
placeholder="Type your to-do here!"
onChange={(e) => this.handleChange(e)}
></input>
<button className="shootbutton">Add!</button>
</div>
</div>
</div>
</form>
{this.state.todos.map((element) => (
<div className="todosoverviewlister" key={element._id}>
<Todoitem id={element._id} title={element.title} />
<button
className="tododelete"
onClick={() => this.handleDelete(element._id)}
>
Delete
</button>
</div>
))}
</DefaultLayout>
</div>
);
}
}
export default Todo;
I believe the issue is that you're not updating the state when you submit (during the add operation). In your delete, you correctly keep the list in state synced with the list on the server by removing the element locally as well. In the add, you should to something similar by adding the new element to the list in state (or more precisely, make a deep copy and overwrite the one in state). That should do it.
There is no need to refetch the entire list from the server unless there are multiple users operating on the same list. If that's the case, you can add a get() call in the response of your submit. As long as the response of that operation writes to state, it will update correctly. But again, avoid that unless you need it as it will make your app slower and less responsive.

Display Dynamic Data in Render Method

I need to create a Card that is dynamically created by populating data from an API. I am able to get this data but I am unable to show the view in the render method.
Kindly assist me to fix my code.
Below is my class Component where I use axios to get a form data, then I iterate through to get the key and value and assign it to the card i want to display. Now I cannot seem to see the Card at all.
class Cards extends Component {
constructor(props) {
super(props);
this.state = { users: [] }
}
componentDidMount() {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
let rows = []
let count = 0
for (var i = 0; i < response.data.length; i++) {
console.log("data: "+response.data[i].key);
rows.push(<div className="col-md-4">
<div className="card">
<p>Data {count++}</p>
<h1>{response.data[i].key}</h1>
<p>{response.data[i].value}</p>
</div>
</div>
)
this.setState({ users: rows })
}
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="cards">
{this.users}
</div>
);
}
}
export default Cards;
It's not a good practice to add HTML tags into the state Instead, add your API response to the state and use the render() to render the data in proper HTML tags.
class Cards extends Component {
constructor(props) {
super(props);
this.state = {
response: {},
};
}
const apiCall = () => {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
this.setState({ response: response });
}).catch((error) => {
console.err(error);
});
}
componentDidMount() {
apiCall();
}
render() {
const { response } = this.state;
return (
<div className="cards">
{response.data.map((item, index) => {
<div key={`user-${index}`} className="col-md-4">
<div className="card">
<p>Data {index+1}</p>
<h1>{item.key}</h1>
<p>{item.value}</p>
</div>
</div>
})}
</div>
);
}
}
export default Cards;
class Cards extends Component {
constructor(props) {
super(props);
this.state = { users: [] };
}
componentDidMount() {
let formData = new FormData();
const username = localStorage.getItem("username");
formData.append("username", username);
const config = {
headers: { "content-type": "multipart/form-data" },
};
axios
.post("http://", formData, config)
.then((response) => {
this.setState({ users: response.data });
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<div className="cards">
{this.state.users?.map((user, id) => (
<div className="col-md-4" key={user.key}>
<div className="card">
<p>Data {id}</p>
<h1>{user.key}</h1>
<p>{user.value}</p>
</div>
</div>
)}
</div>
);
}
}
export default Cards;

Calling a function in another function that is transferred to another component

My goal is to call the function performSearch () by clicking div in the componentItem. The performSerach () function is placed in another select () function. The select () function is passed to the Item component. In console.log returns me active = null.
Items
class Items extends Component {
constructor (props) {
super(props);
this.state = {
items: [],
active: null,
abc: null
}
}
select = (id) => {
this.setState({
abc: id
})
this.performSearch(id);
}
componentDidMount() {
axios.get
axios({
url,
method: "GET",
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => {
this.setState({
items: res.data
});
})
.catch(error => {
console.log(error);
})
}
performSearch = (id) => {
axios.get
axios({
url: `https://app.com/api/v1/${id}`,
method: "GET",
headers: {
'Authorization': `Bearer ${token}`
}
})
.then(res => {
this.setState({
active: res.data
});
})
.catch(error => {
console.log(error);
})
}
render () {
<div>
{this.state.items.map((item, index) =>
<Item
select={this.select}
/>
)}
</div>
}
}
Item
class Item extends Component {
render () {
return (
<div onClick={()=> this.props.select(this.props.item.id)}>
</div>
)
}
}
render () {
<div>
{this.state.items.map((item, index) =>
<Item
select={this.select}
/>
)}
</div>
}
Should pass the item the Item component:
render () {
<div>
{this.state.items.map((item, index) =>
<Item
select={this.select}
item={item}
key={index}
/>
)}
</div>
}
Or:
render () {
<div>
{this.state.items.map((item, index) =>
<Item
select={() => this.select(item.id)}
/>
)}
</div>
}

Post request in react

Unable to send POST request by using fetch method
I am able to fetch request from the server but unable to Post the request dynamically. I am taking input value but it showing the error below:
Error: SyntaxError: "JSON.parse: unexpected character at line 1 column 1 of the JSON data"
const url = "http://some domain/api/tweets";
const input = {tweet: {body: ''}};
class App extends Component{
constructor(props){
super(props);
this.state={
error:null,
isLoaded:false,
data: [],
value: ''
}
this.onSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e){
this.setState({value: e.target.value});
}
componentDidMount() {
fetch("http://some domain/api/tweets")
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result.data
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
handleSubmit(e){
e.preventDefault()
fetch(url, {
method: 'POST',
body: JSON.stringify(this.state.value),
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));
}
render(){
const { error, isLoaded, data } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="list-type5">
<form onSubmit={this.onSubmit} >
<input type="text" placeholder="Body" value={this.state.value} onChange={this.handleChange}/>
<input type="submit" />
</form>
<ol>
{data.map(i => (
<div key={i.id}>
<li >
<a> <b> ID:</b> {i.id} | <b> Body:</b> {i.body} | <b> Views:</b> {i.views} </a>
</li>
</div>
))}
</ol>
</div>
);
}
}
}
export default App;
Help would be appreciated.
I just changed and remove const input = {tweet: {body: ''}}; from top and write it into the handleSubmit function just check it below:-
handleSubmit(e){
e.preventDefault()
const input = {tweet: {body: this.state.value}};
fetch(url, {
method: 'POST',
body: JSON.stringify(input),
headers:{
'Content-Type': 'application/json'
}
}).then(res => res.json())
.then(response => console.log('Success:', JSON.stringify(response)))
.catch(error => console.error('Error:', error));
}
handleSubmit(e) {
fetch("http://some domain/api/tweets", { /*your object...*/ })
.then(res => res.text()) // previous .then(res => res.json())
.then(text => console.log(text))
...
}
The res.json() call seems to be wrong at this place, as your response might not be a valid JSON object. Maybe try res.text() instead and console.log your response to see what it tells you.
More infos about the response object you can find over here: MDN - Response Object

Categories