Objs not valid as children - reactjs

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>
))}
</>
);
}
}

Related

Using setState inside a arrow function resets state

I am trying to modify a state when a users input fields on my dashboard is changed. This is how the handler is intended to work:
If the state is empty. Create a user with the standard values and change its values to the changed inputs
If the user exists in the state, change the changed field in the state to the new value.
If the user does not exist. Add the user to the state and change the changed field to the new value.
I am doing this by calling this function on a change of any inputs:
const handleInputChange = (event, person) => {
let new_form_val = {
objectId: person._id,
name: person.name,
role: person.role,
privilege: person.privilege,
group: person.group
};
console.log("handle change function called")
if (formValues.length == 0)
{
console.log("formValues is empty")
new_form_val[event.target.name] = event.target.value
console.log("adding", new_form_val)
setFormValues([...formValues, new_form_val])
}
// console.log(event.target.value)
console.log("Change target id", event.target.id)
console.log("current formvalue before change", formValues)
let form_val = formValues.find((item) => item.objectId == event.target.id)
if (form_val) {
console.log("person found in formValues", form_val)
let index = formValues.indexOf(form_val)
formValues[index][event.target.name] = event.target.value
console.log("Changed already existing formvalue", formValues)
setFormValues(formValues)
}
else {
new_form_val[event.target.name] = event.target.value
console.log("new person in form value", new_form_val)
setFormValues([...formValues, new_form_val])
}
}
Later on I am using that function as an onChange event handler
useEffect(() => {
// GARL: https: //bobbyhadz.com/blog/react-push-to-state-array
setPeople([])
console.log("get users effetct ran")
axios.get('/api/getusers').then((response) => {
response.data.forEach((item, index) => {
setPeople(oldStatusArray => {
return [...oldStatusArray, <Person
key={index}
id={index+1}
_id={item._id}
name={item.name}
role={item.role}
privilege_id={item.privilege}
group_id={item.group}
onChange={(event) => handleInputChange(event, item)}
/>]
})
});
})
}, []);
The problem I am facing though is whenever the onChange function is called. The whole formValues sate is reset and replaced with the new changed state. For exmpale: I change user A to a new name and role and the change is logged to the console. I also Change User B and then C to a new group. Finally the state only has the changes made from C.
Here is the full code:
import Link from 'next/link';
import axios from 'axios';
import React, { useState, useEffect } from "react";
import Person from '../components/person' // Not actually a import
const Dashboard = () => {
const [people, setPeople] = useState([]);
const [formValues, setFormValues] = useState([]);
const handleInputChange = (event, person) => {
let new_form_val = {
objectId: person._id,
name: person.name,
role: person.role,
privilege: person.privilege,
group: person.group
};
console.log("handle change function called")
if (formValues.length == 0)
{
console.log("formValues is empty")
new_form_val[event.target.name] = event.target.value
console.log("adding", new_form_val)
setFormValues([...formValues, new_form_val])
}
// console.log(event.target.value)
console.log("Change target id", event.target.id)
console.log("current formvalue before change", formValues)
let form_val = formValues.find((item) => item.objectId == event.target.id)
if (form_val) {
console.log("person found in formValues", form_val)
let index = formValues.indexOf(form_val)
formValues[index][event.target.name] = event.target.value
console.log("Changed already existing formvalue", formValues)
setFormValues(formValues)
}
else {
new_form_val[event.target.name] = event.target.value
console.log("new person in form value", new_form_val)
setFormValues([...formValues, new_form_val])
}
}
useEffect(() => {
setPeople([])
console.log("get users effetct ran")
axios.get('/api/getusers').then((response) => {
response.data.forEach((item, index) => {
setPeople(oldStatusArray => {
return [...oldStatusArray, <Person
key={index}
_id={item._id}
name={item.name}
role={item.role}
privilege_id={item.privilege}
group_id={item.group}
onChange={(event) => handleInputChange(event, item)}
/>]
})
});
})
}, []);
const submit = (values) => {
// Submits state to backend for handling
}
return (
<div id="main">
<h1>Administration</h1>
{(people.length == 0) ?
<h1>Laddar innehållet..</h1> : people }
</div>
);
}
export default Dashboard;
Here is the output after changing the input fields a couple of times:
>> handle change function called
>> formValues is empty
>> adding - Object { objectId: "634ea9b368bd856cebfdddc0", name: "RADICATED", role: "...", privilege: "634ff6d42c7b67c5708e901b", group: "634ff7322c7b67c5708e901d" }
>> change target id 634ea9b368bd856cebfdddc0
>> current formvalue before change - Array []
>> new person in form value - Object { objectId: "634ea9b368bd856cebfdddc0", name: "RADICATED", role: "....", privilege: "634ff6d42c7b67c5708e901b", group: "634ff7322c7b67c5708e901d" }
>> CURRENT formvalues - Array [ {…} ] (len: 1)
I have also tried to adding formValues as a dependency to useEffect however, this results in a rerender of the users if I change any of the inputs as the setPeople is called in the useEffect.
How can I achieve a handleInputChange function that works as intended without updating the renderer or reseting the state?
I noticed the step 1 and 3 are actually the same so I put those together. The itemExists check if the person is already in the state. If the state is empty itemExists is false and if the person does not exists itemExists is also false.
When false we just update the field and return the previous and the new new_form_val.
When true we loop over all the current values until we find the one we want to edit, and then update the field we want to update.
const handleInputChange = (event, person) => {
const new_form_val = {
objectId: person._id,
name: person.name,
role: person.role,
privilege: person.privilege,
group: person.group,
};
// check if the item already exists
const itemExists =
formValues.find((item) => item.objectId == event.target.id) !== undefined;
if (itemExists) {
setFormValues((prevFormValues) => {
// map current values
const newValues = prevFormValues.map((item) => {
// if its not the item we're editing just return the item
if (item.objectId !== event.target.id) return item;
// if it is, update the item
const updatedItem = {
...item,
[event.target.name]: event.target.value,
};
return updatedItem;
});
return newValues;
});
} else {
// update the field with the new value
new_form_val[event.target.name] = event.target.value;
// add to the values
setFormValues((prevFormValues) => [...prevFormValues, new_form_val]);
}
};
I also updated the way the people were set. Now we first loop over all the data received from the api and create an array of Person components and set that array to the state, instead of setting the state for every result in the api data.
useEffect(() => {
// no need to set the people to an empty array since the default state is already an empty array
// setPeople([]);
console.log("get users effetct ran");
axios.get("/api/getusers").then((response) => {
const peopleFromApi = response.data.map((item, index) => (
<Person
key={index}
_id={item._id}
name={item.name}
role={item.role}
privilege_id={item.privilege}
group_id={item.group}
onChange={(event) => handleInputChange(event, item)}
/>
));
setPeople(peopleFromApi);
});
}, []);
I hope this helps you continue your project!

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.

How to use multiple or two state values in one component or class file in react JS?

I am trying to use state to hide Semantic-UI Model form also to pass JSON to Customer class to add new customer. I am able to pass the value but in the end there is only one value.
When I start typing name, in console panel on 1st character name is empty "" and on 2nd character there is single "a"
In address
on create button click
when i click create button the name is empty"" and address has value.
import React from 'react';
import { Button, Form, Modal } from 'semantic-ui-react';
export default class AddCustomer extends React.Component {
constructor(props) {
super(props);
this.state = {
showCreateForm:false,
formData:{
name: '',
address: ''
}
}
this.handleChangeName = this.handleChangeName.bind(this);
this.handleChangeAddress = this.handleChangeAddress.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChangeName(event) {
const value = event.target.value;
console.log(value);
this.setState({formData:{name:value}});
//when i go to add input the formData is still empty name is empty.
//name: ""
//address: ""
console.log(this.state.formData);
}
handleChangeAddress(event) {
const value = event.target.value;
console.log(value);
this.setState({formData:{address:value}});
//name: "ram" but now there is no address in formData
console.log(this.state.formData);
}
handleSubmit(event) {
event.preventDefault();
////address: "aaaaa" now there no name in formData
console.log(this.state.formData);
this.setState({formData:{
name:this.state.name, address:this.state.address
}});
this.props.onAddFormSubmit(this.state.formData);
}
//On cancel button click close Create user form
closeCreateForm = () => {
this.setState({ showCreateForm: false })
}
//Open Create new Customer form
openCreateCustomer = () => {
this.setState({ showCreateForm: true })
}
render() {
return (
<div>
<Modal closeOnTriggerMouseLeave={false} trigger={
<Button color='blue' onClick={this.openCreateCustomer}>
New Customer
</Button>
} open={this.state.showCreateForm}>
<Modal.Header>
Create customer
</Modal.Header>
<Modal.Content>
<Form onSubmit={this.handleSubmit}>
<Form.Field>
<label>Name</label>
<input type="text" placeholder ='Name' name = "name"
value = {this.state.name}
onChange = {this.handleChangeName}/>
</Form.Field>
<Form.Field>
<label>Address</label>
<input type="text" placeholder ='Address' name = "address"
value = {this.state.address}
onChange = {this.handleChangeAddress}/>
</Form.Field>
<br/>
<Button type='submit' floated='right' color='green'>Create</Button>
<Button floated='right' onClick={this.closeCreateForm} color='black'>Cancel</Button>
<br/>
</Form>
</Modal.Content>
</Modal>
</div>
)
}
}
With these lines you are replacing your whole state with the value of one field:
Your initial state:
state = {
formData: {
name: "",
address: ""
}
}
Your state after this line:
this.setState({formData:{address:value}});
state = {
formData: {
address: ""
}
}
And with this line:
this.setState({formData:{name:value}});
state = {
formData: {
name: ""
}
}
As mentioned in the answer by Greg b, you have to change the value of the specific key and copy rest as they are. You can also use spread operator to copy rest of the unmodified fields easily.
this.setState({...this.state.formData, address: value})
will only change the address and copy rest of the state as it is. This comes handy when you have multiple fields in the state.
This is your state
formData:{
name: '',
address: ''
}
Change both these lines respectively
this.setState({formData:{address:value}});
this.setState({formData:{name:value}});
To
this.setState({formData:{name: this.state.formData.name, address:value}});`
this.setState({formData:{name:value, address: this.state.formData.address}});`
function handleChangeName(event) {
const value = event.target.value;
this.setState((prevState)=>({ formData: { name: value, address: prevState.formData.address }}),
()=>{ console.log(this.state.formData)});
}
function handleChangeAddress(event) {
const value = event.target.value;
this.setState((prevState)=>({ formData: { name: prevState.formData.name, address: value}}),
()=>{ console.log(this.state.formData)});
}
if you what to something next after setState() or state update, you have to use call back function.
State Updates are Merged
It looks like you aren't accessing the state correctly in the render(), I see you doing this.state.name and this.state.address rather than this.state.formData.nameand this.state.formData.address.
Also you probably shouldn't be storing your form data in a single state object, break it out into a field for each input, e.g.
this.state = {
showCreateForm: false,
name: "...",
address: "..."
}
You cannot update only part of an object in state, you need to update the whole thing. When you do this.setState({formData:{address:value}}); or are essentially setting this.state.formData.name to undefined, since the object is now going to only be { address: value }

Using Reactjs to show Json response data on each form submission

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

Resources