How to read and change big arr in React - javascript

I have a state that contains another array. I need to get this array to return it as a list. The new Item should appear as an object in the application array. I don't quite understand what I did wrong. How can I fix this?
** enter image description here
import React, { useState } from 'react'
function App() {
const [data, setData] = useState([
{
name: 'Ivan Pupkin',
email: 'ivan#gmail.com',
phone: '+34452344323',
application: [
{
nameOfApp: 'Name of App',
type: 'It and business',
description: 'some description',
},
],
},
])
const [name, setName] = useState('');
const [type, setType] = useState('');
const [description, setDescription] = useState('');
const addNewUser = (e) => {
e.preventDefault()
setData(current => current.map(item => [...item.application, {
personalId: 4,
nameOfApp: name,
description: description,
type: type
}]))
}
const Users = data.map(item => item.application.map((elem, index) => {
return(
<div key={index}>
<div>{elem.nameOfApp}</div>
<div>{elem.type}</div>
<div>{elem.description}</div>
</div>
)
}))
return (
<div>
<form action="#">
<input onChange={(e) => setName(e.target.value)} placeholder='name'/>
<input onChange={(e) => setType(e.target.value)} placeholder='type'/>
<input onChange={(e) => setDescription(e.target.value)} placeholder='desc'/>
<button onClick={addNewUser} type='submit'>submit</button>
</form>
<br />
<br />
<br />
{Users}
</div>
)
}
export default App

I'm not sure if I've understand what you're tring to do but here is a working version :
Basically, I just say which user I want to edit in addUser() then search it, assign new application to it, and return the array of users without the previous user
If I were you, I would avoid to have objects / array without ids :)
import React, { useState } from "react";
function App() {
const [data, setData] = useState([
{
id: 1,
name: "Ivan Pupkin",
email: "ivan#gmail.com",
phone: "+34452344323",
application: [
{
id: 1,
nameOfApp: "Name of App",
type: "It and business",
description: "some description"
}
]
}
]);
const [name, setName] = useState("");
const [type, setType] = useState("");
const [description, setDescription] = useState("");
const addNewUser = (e, targetUserId) => {
e.preventDefault();
setData((prevUsers) => {
const editedUser = prevUsers.find(({ id }) => id === targetUserId);
editedUser.application.push({
nameOfApp: name,
type: type,
description: description
});
const newUsers = [
...prevUsers.filter(({ id }) => id !== targetUserId),
editedUser
];
return newUsers;
});
};
const Users = data.map((item) =>
item.application.map((elem, index) => {
return (
<div key={index}>
<div>{elem.nameOfApp}</div>
<div>{elem.type}</div>
<div>{elem.description}</div>
</div>
);
})
);
return (
<div>
<form action="#">
<input onChange={(e) => setName(e.target.value)} placeholder="name" />
<input onChange={(e) => setType(e.target.value)} placeholder="type" />
<input
onChange={(e) => setDescription(e.target.value)}
placeholder="desc"
/>
<button onClick={(e) => addNewUser(e, 1)} type="submit">
submit
</button>
</form>
<br />
<br />
<br />
{Users}
</div>
);
}
export default App;
Hope it helped you !

Related

Add an object to an array upon submitting form in react

I am new to react and I am just playing around with some code to familiarize myself with it.
I have data stored into an array of objects, as if I was bringing it in from a JSON-based API. I am using states so I can remove or add any item to the data.
I have succeeded to remove an element from the array of objects. To add to the list, I am using a form. I have my form setup in Form.js.
Form.js
import { useState } from "react";
function Form() {
const [name, setName] = useState("");
const [job, setJob] = useState("");
const submitForm = (e, {handleSubmit}) => {
e.preventDefault();
const newChar = {
name: e.target.name.value,
job: e.target.job.value
}
handleSubmit(newChar);
setName('');
setJob('');
}
return (
<form onSubmit={submitForm}>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
id="name"
value={name}
onChange={(e) => setName(e.target.value)} />
<label htmlFor="job">Job</label>
<input
type="text"
name="job"
id="job"
value={job}
onChange={(e) => setJob(e.target.value)} />
<input type="submit"/>
</form>
);
}
export default Form;
In App.js, I have initialized my array of objects and I have my function handleSubmit() that will update the state by taking the existing state and adding the new character parameter, using the ES6 spread operator.
import { useState } from "react";
import Form from "./Form";
function App() {
const [characters, setCharacters] = useState([
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]);
const removeChar = (id) => {
const newChars = characters.filter(character => characters.indexOf(character) !== id);
setCharacters(newChars);
}
const handleSubmit = (character) => {
setCharacters([ ...characters, character ]);
}
return (
<div className="container">
<Table characters = {characters} removeChar = {removeChar} />
<Form handleSubmit = {handleSubmit} />
</div>
);
}
export default App;
This code does not work. I cannot seem to figure out why. any help would be greatly appreciated
just try this
const handleSubmit = (character) => {
let oldArray = [...characters]
oldArray.push(character)
setCharacters(oldArray);
}
Check this Example
characters = [
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]
const handleSubmit = (character) => {
let oldArray = [...characters]
oldArray.push(character)
console.log(oldArray)
//setCharacters([ ...characters, character ]);
}
handleSubmit({name:'Waleed',Job:"HOD"})
So I found where the problem was lying. I was passing the {handleSubmit} in the const SubmitForm declaration instead of passing it to the const Form() .
Here is the code if it can help anyone new to react.
Form.js
import { useState } from "react";
function Form({handleSubmit}) {
const [name, setName] = useState("");
const [job, setJob] = useState("");
const submitForm = (e) => {
e.preventDefault();
const newChar = {
name: e.target.name.value,
job: e.target.job.value
}
handleSubmit(newChar);
setName('');
setJob('');
}
return (
<form onSubmit={submitForm}>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
id="name"
value={name}
onChange={(e) => setName(e.target.value)} />
<label htmlFor="job">Job</label>
<input
type="text"
name="job"
id="job"
value={job}
onChange={(e) => setJob(e.target.value)} />
<input type="submit"/>
</form>
);
}
export default Form;
App.js
import { useState } from "react";
import Form from "./Form";
function App() {
const [characters, setCharacters] = useState([
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]);
const handleSubmit = (character) => {
setCharacters(characters => [...characters, character])
}
return (
<div className="container">
<Form handleSubmit = {handleSubmit} />
</div>
);
}
export default App;

react input form returns undefined

it updates only the lastly typed input box value in the state and other are undefined
i get this in console
Object { Name: undefined, Age: "123", City: undefined }
second time
Object { Name: undefined, Age: undefined, City: "city" }
Form.jsx
import React, {useState} from 'react';
const Form = (props) => {
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
[e.target.name]: e.target.value,
})
}
const infoSubmit = e =>{
e.preventDefault();
let data={
Name:formData.Name,
Age:formData.Age,
City:formData.City
}
props.myData(data);
}
return (
<div className="">
<form onSubmit={infoSubmit} autoComplete="off">
<div className="form-group mb-6">
<label className="">Name:</label>
<input type="text" onChange={infoChange} name="Name" value={formData.Name} className=""placeholder="Enter Name" />
</div>
<div className="form-group mb-6">
<label className="">City:</label>
<input type="text" onChange={infoChange} name="City" value={formData.City} className=""
placeholder="Enter Age" />
</div>
<button type="submit" className="">Submit</button>
</form>
</div>
);
};
export default Form;
App.jsx
this is App.jsx file, here i get the data prop and display it in console.log
import React from 'react';
import Form from './components/Form';
import Table from './components/Table';
const App = () => {
const create = (data) => {
console.log(data);
}
return (
<div className='flex w-full'>
<div className=''>
<Form myData={create} />
</div>
<div className=''>
<Table />
</div>
</div>
);
};
export default App;
You're stomping the previous state with the most recent change. If you want to preserve the existing state you have to include it in the update.
setFormData({
...formData,
[e.target.name]: e.target.value,
})
with react-hooks you need to set the entire object again.
const [formData, setFormData] = useState({ Name:'', Age:'', City:''});
const infoChange = e => {
const { name,value} = e.target;
setFormData({
// spread the current values here
...formData,
// update the current changed input
[name]: value,
})
or, even better IMHO. You have one state for each prop
const [name, setName] = useState('');
const [age, setAge] = useState('');
const [city, setCity] = useState('');
// ...
<input onChange={({target: {value}}) => setName(value)} />
<input onChange={({target: {value}}) => setAge(value)} />
<input onChange={({target: {value}}) => setCity(value)} />
Change this
const infoChange = e => {
const { name,value} = e.target;
setFormData({...formData
[e.target.name]: e.target.value,
})
}

when i try to submit a form its is showing TypeError: Object(...) is not a function

this is my simple book-list application using react context API. I have created a context to addBook, removeBook, and entire Book state and provide to other components.
when I try to add a book via a form it shows TypeError: Object(...) is not a function
below is my book context where I have created a context for addBook, removeBook, and entire BookState and provided it to its wrapping child components
BookContext.js
import React, { createContext, useState } from 'react';
import {uuid} from 'uuid/dist/v1';
export const BookContext = createContext();
const BookContextProvider = ({ children }) => {
const [books, setBooks] = useState([
{ id: 1, title: 'name of wind', author: 'Elizabath' },
{ id: 2, title: 'the narrow bridge', author: 'Mc clary' },
]);
const addBook = (title, author) => {
setBooks([...books, { id: uuid(),title, author }])
};
const removeBook = (id) => {
setBooks(books.filter((book) => book.id !== id))
};
return (
<BookContext.Provider
value={{ books, addBook, removeBook }}
>
{children}
</BookContext.Provider>
);
};
export default BookContextProvider;
below is my bookForm.js file where I have consumed context from the provider and destructured addBook from it
BookForm.js
import React, { useContext, useState } from 'react';
import { BookContext } from '../Contexts/BookContext';
function BookForm() {
const { addBook } = useContext(BookContext);
const [title, setTitle] = useState('');
const [author, setAuthor] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
addBook(title, author)
setTitle('')
setAuthor('')
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Book Name"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
<input
type="text"
placeholder="Author Name"
value={author}
onChange={(e) => setAuthor(e.target.value)}
required
/>
<input type="submit" value="add Book" />
</form>
);
}
export default BookForm;
Your code appears to be working fine. I believe the issue lies in a separate part. I'd suggest following the stack trace of the error as that should give you a better location of the error. Or there's more to the context provider than you included on this.
There might be another component that uses the books that are added that throws when a new book is added.
const { createContext, useContext, useState } = React;
const uuid = uuidv1;
const BookContext = createContext();
const BookContextProvider = ({ children }) => {
const [books, setBooks] = useState([
{ id: 1, title: "name of wind", author: "Elizabath" },
{ id: 2, title: "the narrow bridge", author: "Mc clary" },
]);
const addBook = (title, author) => {
setBooks([...books, { id: uuid(), title, author }]);
};
const removeBook = (id) => {
setBooks(books.filter((book) => book.id !== id));
};
return (
<BookContext.Provider value={{ books, addBook, removeBook }}>
{children}
</BookContext.Provider>
);
};
function BookForm() {
const { addBook } = useContext(BookContext);
const [title, setTitle] = useState("");
const [author, setAuthor] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
addBook(title, author);
setTitle("");
setAuthor("");
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Book Name"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
<input
type="text"
placeholder="Author Name"
value={author}
onChange={(e) => setAuthor(e.target.value)}
required
/>
<input type="submit" value="add Book" />
</form>
);
}
function Books() {
const { books } = useContext(BookContext);
return (
<div>
{books.map(({ id, title, author }) => (
<div key={id}>
{title} - {author}
</div>
))}
</div>
);
}
ReactDOM.render(
<BookContextProvider>
<BookForm />
<Books />
</BookContextProvider>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uuid/8.3.2/uuidv1.min.js" integrity="sha512-4hJwRX3o1o5dU3A+ffhCQpLzOT7U0wDoR9Ha7McoxXez011iFJ6RMB08BrzE23G+gB3gNriotihq7TPIf7x/NA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div id="root" />

how to filter array in reactJS with 2 condistions

I try to filter the array with two conditions but without success, it only refers to the second condition, each condition individually works great.
The original task :
"When entering a text in the “search” text box, the users list will presents anly users that
their name or email contains that text
const filteredUsers = this.state.users.filter((filuser) => {
return (
filuser.name.toLowerCase().includes(this.state.searchfield.toLowerCase()) ||
filuser.email.toLowerCase().includes(this.state.searchfield.toLowerCase())
);
});
const filteredUsers = this.state.users.filter((filuser) => {
const {searchfield} = this.state
return (
`${filuser.name} ${filuser.email}`.toLowerCase().indexOf(searchfield)>-1
});
I'm sharing my way to multiple filter data.https://codesandbox.io/s/summer-wildflower-fuio1?file=/src/App.js
Move the constant data to outside of component and state have only filtered data. Each time when you apply the filters, always use the initial data (all_data).
Here is update code. (try name abc and email def, it will show 2 results)
https://codesandbox.io/s/confident-leavitt-t2wsr
import { useState } from "react";
import "./styles.css";
const all_data = [
{
names: "abc",
emails: "abc#gmail.com"
},
{
names: "def",
emails: "def#gmail.com"
},
{
names: "ghi",
emails: "ghi#gmail.com"
}
];
export default function App() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [data, setData] = useState(all_data);
const nameFilter = ({ names }) =>
names.toUpperCase().includes(name.toUpperCase());
const emailFilter = ({ emails }) =>
emails.toUpperCase().includes(email.toUpperCase());
const handleSearch = () => {
// const filterData = data.filter(nameFilter).filter(emailFilter);
const filterData = all_data.filter(
(obj) => nameFilter(obj) || emailFilter(obj)
);
setData(filterData);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<input
type="text"
placeholder="name"
onChange={(e) => setName(e.target.value)}
/>
<input
type="text"
placeholder="email"
onChange={(e) => setEmail(e.target.value)}
/>
<button onClick={handleSearch}>Search</button>
{data.map((item, i) => {
return (
<div key={i}>
<p>{item.names}</p>
<p>{item.emails}</p>
</div>
);
})}
<h2>Start editing to see some magic happen!</h2>
</div>
);
}

Extra item being added in localStorage?

I am trying to build message component in react. Currently I just saving entered messages in localStorage but whenever I am pushing a message 2 rows get pushed in localStorage which should not happen. I have checked it but not able to get why this happening.
message comp
import React, { useState, useEffect } from "react";
interface IMessage {
user: string;
text: string;
}
export const Message = () => {
const [messages, setMessages] = useState<IMessage[]>([]);
const [message, setMessage] = useState("");
const [user, setUser] = useState("testuser");
useEffect(() => {
const fetchedMessages = JSON.parse(localStorage.getItem("messages") as any);
if (fetchedMessages) {
console.log("fetchedMessages=>", fetchedMessages);
}
}, [messages]);
const handleFormSubmit = (event: any) => {
event.preventDefault();
setMessages((messages) => {
const newData = [...messages, { text: message, user: user }];
let oldStorage =
JSON.parse(localStorage.getItem("messages") as any) || [];
const oldStorageN = [...oldStorage, { text: message, user: user }];
localStorage.removeItem("messages");
localStorage.setItem("messages", JSON.stringify(oldStorageN));
return newData;
});
setMessage("");
};
return (
<>
<div className="MessageContainer">
{messages.map((message) => {
return (
<div key={message.text + message.user}>
<div>
<strong>{message.user}</strong>
<div>{message.text}</div>
</div>
</div>
);
})}
</div>
<div>
<form onSubmit={handleFormSubmit}>
<div>
<input
type="text"
name="message"
onChange={(e) => {
setMessage(e.target.value);
}}
value={message}
/>
</div>
<div>
<input type="submit" value="send" />
</div>
</form>
</div>
</>
);
};
This is code link
https://stackblitz.com/edit/react-starter-typescript-qowlvq?file=components/Message.tsx
Note: on StackBlitz it's working fine, but on my machine it's adding two entries per message.

Categories