Using Reactjs to show Json response data on each form submission - reactjs

How can I use Reactjs list records response on each form submission.
I have searched for previous post on this on stackoverflow but most solution I found does not address my issue.
The code below works but only list one record or
replace already existing displayed data on each form submission.
Here is what I want to achieve.
If I submit form 4 times am supposed to have 4 records displayed
For Instance
uid filename
1 macofile
2 johnfile
3 lukefile
4 tonyfile
But what this code does is to replace already existing record on each form submission and
as a result, it only show just one records
Eg. on 4th form submission it shows only
4 tonyfile
In angularjs I use something like push function to actualize my goal as per code below
$scope.users.push(res.data[0]);
In reactjs if I try the code below
const users = users.push(res.data);
//const users = users.push(res.data[0]);
it will show error
Cannot read property 'push' of undefined
Here is the code
import React, { Component } from "react";
import axios, { post } from "axios";
class FilePage extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "",
filename: "",
loading: false,
users: [],
error: null
};
this.handleChange = this.handleChange.bind(this);
}
_handleSubmit(e) {
e.preventDefault();
//send it as form data
const formData = new FormData();
formData.append("filename", this.state.filename);
//alert(this.state.filename);
this.setState({ loading: true }, () => {
axios
.post("http://localhost/apidb_react/up.php", formData)
.then(res => {
//const users = res.data;
//const users = users.push(res.data[0]);
const users = users.push(res.data);
this.setState({ users, loading: false });
/*
this.setState({
users: res.data,
loading: false
});
*/
})
.catch(err => {
console.log(err.message);
});
});
}
// handle form submission
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
render() {
const { loading, users, error } = this.state;
return (
<div>
<form onSubmit={e => this._handleSubmit(e)}>
<b>filename:</b>
<input
tyle="text"
className="form-control"
value={this.state.filename}
name="filename"
onChange={this.handleChange}
/>
<button
className="submitButton"
type="submit"
onClick={e => this._handleSubmit(e)}
>
submit
</button>
</form>
<ul>
{this.state.users.map((user, index) =>
<option key={user.uid} value='{ user.uid }' > { user.uid } { user.filename}</option>
)}
</ul>
</div>
);
}
}

because the local user is not defined as an array to have .push() function.
const users=this.state.users;
users.push(res.data) then you can replace it with the users in the state.

what works for me is the concat functions as per code below
const users=this.state.users.concat(res.data);
// const users=this.state.users.push(res.data);// does not work.
Consequently, push() does not work because it returns the length of the extended array, instead of the array itself.
Thanks

Related

how to get data from another api and post it with another api in react js

Hi i am working on reactjs with axios. currently i am working on post api and i am working on hybrid form like need some data from get api and some data send by input value. currently i am able to do only one thing. like get value in input field or post value from same input field.but i want to to same thing with one input field. like update field first get data and update it. but in update we use one api and here i m using two api
Post api
handleSubmit = event => {
event.preventDefault();
event.target.reset()
console.log(this.props.rowId);
let rId = this.props.rowId;
const posts = rId;
console.log(posts);
const brokerId = localStorage.getItem("brokerId");
// Based on several assumptions: single obj returned, posts is never empty
axios.post(`http://http:testapi/100/${brokerId}`, {
ipoId: this.props.rowId,
// question: this.state.question,
// answer: this.state.answer,
UCC: this.state.UCC,
NAME: this.state.NAME,
ZONE: this.state.ZONE,
UPDATED_BY: this.state.UPDATED_BY,
// faqList: [
// {
// }
// ]
}).then(res => {
this.getData();
this.setState({
question: ''
})
this.setState({
answer: ''
})
})
.catch(err => {
this.setState({
errorMessage: err.message
});
})
}
handleNAMEChange = event => { this.setState({ NAME: event.target.value }) }
handleUCCChange = event => { this.setState({ UCC: event.target.value }) }
Get Api
getData() {
let rId = this.props.rowId;
axios.get(`http:testapi/100/${rId}`)
.then(res => {
const faq = res.data.body.data.client_detail;
this.setState({
faq
});
})
};
able to get the data from get api in this field
<TextField
type="text"
label="UCC"
value={faqList.clienT_CODE}
name="UCC"
onChange={this.handleUCCChange}
/>
able to post the data from post api in this field
<TextField
type="text"
label="NAME"
value={this.state.NAME}
name="UCC"
onChange={this.handleNAMEChange}
/>

Objs not valid as children

I have created a project that calls out to the WHOIS API ( which takes Domain, IPv4, IPv6, and email address as valid input ) I have this working properly with the domain address input but when I input an IP address this is the error message I get. Error: Objects are not valid as a React child (found: object with keys{}). If you meant to render a collection of children, use an array instead.
Here is my code that is currently working properly with domain inputs
import React from "react";
import axios from "axios";
export default class Form extends React.Component {
//making inputValue an empty string to allow the user input and work with that later
state = {
inputValue: "",
//making data an empty array to display later
data: [],
};
change = (e) => {
this.setState({
//when input is changed set the state of inputValue to the new value given from the form
[e.target.name]: e.target.value,
});
};
onSubmit = (e) => {
//create a constant variable that is called input to shorten up code when using it later
const input = document.getElementsByName("inputValue")[0].value;
//prevent page from refreshing when submit is pressed
e.preventDefault();
//appending the value the user input to trigger my API
var appendInput = "http://localhost:4000/api/whois/" + input;
var getForm = document.getElementById("inputForm");
getForm.action = appendInput;
// this.props.onSubmit(this.state.inputValue);
//at this point this.state is = my userInput
console.log(this.state.inputValue);
console.log("Before GET");
//rename the current state of inputValue into a variable to shorten the code up
const x = this.state.inputValue;
//this is where I use axios to make the call to the backend to then display data
console.log(`${encodeURIComponent(`${x}`)}`);
axios
.get(`http://localhost:4000/api/whois/${encodeURIComponent(`${x}`)}`)
.then((resp) => {
//when the request is successful I want to format the data from a JSON object into an array with key pair values
let k;
let newArr = [];
let newFormat = {};
for (k in resp.data) {
newFormat = { k: k, v: resp.data[k] };
console.log(k);
newArr.push(newFormat);
}
console.log("end", newArr);
console.log(typeof newArr);
console.log(typeof resp.data);
//setting state of data to an array from object
this.setState({ data: newArr });
console.log(this.state.data[0].k);
console.log(this.state.data[0].v);
})
.catch((err) => {
console.log(err);
});
console.log("Finished GET");
// this.setState({
// inputValue: ''
// });
};
render() {
return (
/* Create a form that allows the user to input either a domain or ip address */
<>
<form>
<input
id="inputForm"
name="inputValue"
placeholder="Domain or IP Address"
value={this.state.inputValue}
onChange={(e) => this.change(e)}
/>
<br />
<button className="submitBtn" onClick={(e) => this.onSubmit(e)}>
Submit
</button>
</form>
<br />
{/* THIS FINALLY WORKS! WOOOOOOO */}
{this.state.data.map((data) => (
<p key={data.id}>
{data.k} {data.v}
</p>
))}
</>
);
}
}

How to customer data in value antd and Put axios

How to customer data in value antd and Put axios
https://ant.design/components/form/
The input does not let me change the data that will be updated by axios
I must still be able to fix it.
I want to show Antd form data. I read the review and use initialValues But I still can't.
componentDidMount () {
let id = this.props.match.params.id;
httpClient
.get(`http://localhost:8085/api/v1/customer/customer/${id}`)
.then((e) => this.setState({
cus_fname: e.data.cus_fname,
cus_lname: e.data.cus_lname,
cus_email: e.data.cus_email,
cus_tel: e.data.cus_tel,
cus_car_number: e.data.cus_car_number,
cus_band: e.data.cus_band,
cus_address: e.data.cus_address,
}));
}
onFinish = async(values) => {
// console.log("ค่า values ที่มาจาก form: ", values);
const formData = new FormData();
formData.append("cus_fname", values.cus_fname);
formData.append("cus_lname", values.cus_lname);
formData.append("cus_email", values.cus_email);
formData.append("cus_tel", values.cus_tel);
formData.append("cus_car_number", values.cus_car_number);
formData.append("cus_band", values.cus_band);
formData.append("cus_address", values.cus_address);
await httpClient
.put(`http://localhost:8085/api/v1/customer/customer/`, formData )
.then((res) => {
// console.log(res.data);
// console.log( "PushData to server success : ", res);
}).catch((error) => {
console.log("Error :", error);
});
await this.props.history.goBack();
};
handleChange = event => {
event.persist();
this.setState({
[event.target.fname]: event.target.value
});
};
render() {
const { fname, lname, email, phone, band, cus_address, car_number} = this.state;
return (
<Form {...layout} name="nest-messages" onFinish{this.updateCustomer} >
<FormItem
label="ชื่อ"
name="fname"
defaultValue={fname}
rules={[{ required: true, message: "โปรดระบุชื่อ ", }]}
onChange={this.handleChange}
>
<Input />
</FormItem>
)
initialValues will show only the state value on the first render, it will not change the value of the form on componentDidMount even you did setState because that will be a second render.. to achieve it you need a reference to the form and use the api of the instance.
//create instance
formRef = React.createRef();
componentDidMount () {
let id = this.props.match.params.id;
httpClient
.get(`http://localhost:8085/api/v1/customer/customer/${id}`)
.then((e) => {
this.formRef.current.setFieldsValue({
cus_fname: e.data.cus_fname,
cus_lname: e.data.cus_lname,
cus_email: e.data.cus_email,
cus_tel: e.data.cus_tel,
cus_car_number: e.data.cus_car_number,
cus_band: e.data.cus_band,
cus_address: e.data.cus_address,
});
//you can still do a setState
/*this.setState({
cus_fname: e.data.cus_fname,
cus_lname: e.data.cus_lname,
cus_email: e.data.cus_email,
cus_tel: e.data.cus_tel,
cus_car_number: e.data.cus_car_number,
cus_band: e.data.cus_band,
cus_address: e.data.cus_address,
});*/
})
}
and in the Form component:
<Form ref={this.formRef} {...layout} name="nest-messages" onFinish={this.updateCustomer} >
...
</Form>
take note that there is no onChange callback on <Form.Item> component on antd documentation. If you want to change the state on every change, use onValuesChange props of the Form.
<Form onValuesChange={(changedValues, allValues) => {
/* perform setState */
}}>
</Form>
You may also want to look on this link for more info.

useState referring to stale value

I have a keeper app where I am adding notes and storing them in database. When I make a post request to the server, I am trying to fetch the _id from database, which will eventually help me to later delete the note ( if needed).
Here is my jsx file
function CreateMessage(props) {
const [currentGuest, setCurrentGuest] = useState({
guestName: '',
guestMessage: '',
id:''
});
function handleMessages(event) {
const {name, value} = event.target;
setCurrentGuest(prevGuest => {
return {
...prevGuest,
[name] : value
};
});
}
function submitMessage(event) {
//props.onAdd(currentGuest);
const params = {
guestName: currentGuest.guestName,
guestMessage: currentGuest.guestMessage,
}
axios
.post("http://localhost:8000/notes", params)
.then(res => {
console.log("The response is"+res.data._id);
console.log(res.status);
setCurrentGuest(prevGuest => {
console.log(res.data._id)
return {
...prevGuest,
id: res.data._id
};
});
console.log(currentGuest);
})
event.preventDefault();
}
return (
<div>
<form>
<input
name="guestName"
placeholder="Guest Name"
value={currentGuest.guestName}
onChange={handleMessages}
/>
<textarea
name="guestMessage"
placeholder="Write a Message"
rows="3"
value={currentGuest.guestMessage}
onChange={handleMessages}
/>
<button onClick={submitMessage}>Add</button>
</form>
</div>
);
}
The id is properly being fetched and displayed in ```console.log("The response is"+res.data._id"). But on first submit, the is always empty and stale id gets attached to the currentGuest object on next submit
function submitMessage(event) {
//props.onAdd(currentGuest);
const params = {
guestName: currentGuest.guestName,
guestMessage: currentGuest.guestMessage,
}
axios
.post("http://localhost:8000/notes", params)
.then(res => {
console.log("The response is"+res.data._id);
console.log(res.status);
setCurrentGuest(prevGuest => {
console.log(res.data._id)
return {
...prevGuest,
id: res.data._id
};
});
console.log(currentGuest);
})
event.preventDefault();
}
In the above snippet, after getting the response you're correctly changing the state but the problem is with where you're checking the changed state(console.log(currentGuest)). You're basically logging before the state is changed.
You can use useEffect hook and log the state inside it. This runs every time the currentGuest Changes.
useEffect(() => {
console.log(currentGuest)
}, [currentGuest])
Update
You can use the modified currentGuest inside the useEffect hook:
useEffect(() => {
console.log(currentGuest)
if(currentGuest.id) {
props.onAdd(currentGuest);
// You can also reset the state here as follows
setCurrentGuest({
guestName: '',
guestMessage: '',
id:''
});
}
}, [currentGuest]) // You might need to add the necessary dependencies to this array.

I am getting the error message Warning: Can't perform a React state update on an unmounted component

I am getting the error message
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.in Login (created by Context.Consumer`)
I am have tried the most common fix for that issue but it didn't work. The fix where you use _isMounted = false; componentDidMount() { this._isMounted = true;} if (this._isMounted) {this.setState({ data: data});}
I am also using Context.
SessionContex.js
import React, { Component, createContext } from "react";
export const SessionContext = createContext();
class SessionContextProvider extends Component {
_isMounted = false;
state = {
is_logged_in: false,
personid: " ",
firstname: " ",
lastname: " "
};
loggedIn = (loginvalue, personid, firstname, lastname) => {
this.setState({
is_logged_in: loginvalue,
personid: personid,
firstname: firstname,
lastname: lastname
});
};
loggedOut = () => {
this.setState({
is_logged_in: false,
personid: " ",
firstname: " ",
lastname: " "
});
};
componentDidMount = () => {
this._isMounted = true;
const login = localStorage.getItem("is_logged");
const id = localStorage.getItem("personid");
const firstname = localStorage.getItem("firtname");
const lastname = localStorage.getItem("lastname");
console.log(login);
if (this._isMounted) {
this.setState({
is_logged_in: login,
personid: id,
firstname: firstname,
lastname: lastname
});
}
};
componentWillUnmount() {
this._isMounted = false;
}
render() {
return (
<SessionContext.Provider
value={{
...this.state,
loggedIn: this.loggedIn,
loggedOut: this.loggedOut
}}
>
{this.props.children}
</SessionContext.Provider>
);
}
}
export default SessionContextProvider;
Login.jsx
import React, { Component } from "react";
import { SessionContext } from "../context/SessionContext";
import "../Stylesheets/Login.css";
import "..//Stylesheets/global.css";
import { Redirect } from "react-router-dom";
class Login extends Component {
_isMounted = false;
static contextType = SessionContext;
state = {
password: " ",
email: " ",
couldNotfindLogin: true,
redirect: false
};
handleChange = e => {
this.setState({
[e.target.name]: e.target.value,
[e.target.name]: e.target.value
});
};
handleSubmit = async e => {
e.preventDefault();
const data = this.state;
console.log(data);
const response = await fetch("http://localhost:3080/users/login", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
const reply = await response;
if (reply.status === 200) {
const userData = await response.json();
this.context.loggedIn(
userData.isValid,
userData.personid,
userData.firstname,
userData.lastname
);
localStorage.setItem("is_logged", userData.isValid);
localStorage.setItem("personid", userData.personid);
localStorage.setItem("firstname", userData.firstname);
localStorage.setItem("lastname", userData.lastname);
this.setState({
couldNotfindLogin: true,
redirect: true
});
}
if (reply.status !== 200) {
this.context.loggedIn(false);
console.log(this.context);
}
this.setState({
couldNotfindLogin: false
});
};
componentWillUnmount() {
this.mounted = false;
}
render() {
let { couldNotfindLogin } = this.state;
if (this.state.redirect === true) {
return <Redirect to="/" />;
}
return (
<>
<section className="container">
<div className="row">
<div className="col-sm-12 col-md-12 col-lg-12 login-section">
<div className="form login-box">
<form className="form-login Login" onSubmit={this.handleSubmit}>
<label htmlFor="Email">
<p className="login-header">
Login to see your past, present, and future self.
</p>
<input
className="login-input"
id="Email"
type="text"
name="email"
onChange={this.handleChange}
placeholder="Email Address"
required
/>
{!couldNotfindLogin ? (
<p className="FindYou">We could not find your account </p>
) : (
" "
)}
</label>
<label htmlFor="Password">
<input
className="login-input"
id="Password"
type="password"
name="password"
onChange={this.handleChange}
placeholder="Password"
required
/>
</label>
<button className="login-button" type="submit">
Login
</button>
</form>
</div>
</div>
</div>
</section>
</>
);
}
}
I found a few mistakes that are holding you back. I'll try to brief as to not make this a long-winded answer:
Allow the Provider to handle all things related to high-level state and localStorage. Only use local state that's revelant to the component. Also, since setState() is asynchronous, avoid setting it immediately following another asynchronous function(s). While you do have an _isMounted class property, it isn't being checked against when the async function (fetch request) resolves, therefore if you're redirecting the user to another route while React attempts to update the component state, then you'll get these warnings as described above. Put simply, utilize the _isMounted in the async function right before using setState or simply avoid using setState (see example below).
The handleChange class field only needs a single [e.target.name]: e.target.value statement. Having two is unnecessary. You can use object destructuring to simplify this down to: [name]: value (see example below).
Any component provided to a Route has access to some route props. Among the props is a history object that contains several methods -- among them is a push method. You can use this push method to redirect a user to another url: this.props.history.push("url"). Again this is provided, by default, to a component that resides in a react-router-dom Route.
async/await will only work on promises. Therefore, you'll want to await the initial fetch response and then await the fetch response.json() promise. The first promise, returns a Stream object, while the second promise returns a JSON object (this is by design, other libraries, like axios, skip this second promise). Therefore, const reply = await response; expression isn't necessary as it's not waiting for promise a resolve, but instead it's just setting the response's Stream object to a reply variable.
Lastly, only use let for variables if you plan on updating or mutating this variable dynamically within the same execution cycle; otherwise, just use const. This becomes especially important because state and props should always be immutable for React to know when or if they have been updated (via another component or by setState). Simply put, avoid using let for state/prop expressions like: let { password } = this.state.
Working example (I'm mimicking the fetch response promise, but you can play around with it by checking out the src/api/index.js file -- for example you can trigger an error response by submitting a password as invalid):

Resources