react js adding object to state array - javascript

Testing some things in React js and having some issues with some of my logic. I am trying to get value from inputs in a form then on submitting that form i want to take that object of input values and add them to my ctcList array. I am trying to use the es6 features of spread for concating my current newCtc state with my ctcList state. When i console log i get the newCtc values but then the ctcList array is empty. Any help is appreciated.
Thank you!
import React, { Component } from 'react';
import Contact from './Contact';
import TestData from './TestData';
class ContactList extends Component {
constructor(props){
super(props);
this.state = {
name: '',
test1:'',
test2:'',
newCtc:{},
ctcList:[],
arr: []
}
}
async componentDidMount() {
try{
const result = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await result.json()
this.setState({arr:data})
}catch(err){
console.log(err)
}
}
onChangeInput = (e)=>{
const target = e.target;
const name = target.name;
const value = target.value;
console.log(value)
this.setState({
[name]: value
});
}
newSubmit = (e) =>{
e.preventDefault();
this.setState(Object.assign(this.state.newCtc,{test1:this.state.test1, test2:this.state.test2}));
console.log(this.state.newCtc)
this.addContact();
this.clearInput();
console.log(this.state.newCtc);
}
addContact = ()=>{
this.setState({ ctcList:[ ...this.state.ctcList, this.state.newCtc] });
console.log(this.state.ctcList);
};
clearInput = ()=>{
this.setState({test1:'',test2:''});
this.setState(Object.assign(this.state.newCtc,{test1:'', test2:''}));
};
render() {
return (
<div>
<Contact firstName = {this.state.name} lastName='mcdaniel' phoneNumber = '585-721-3824' />
<input type = 'text' name = 'name' onChange = {this.onChangeInput}></input>
<TestData data={this.state.arr} />
<form onSubmit = {this.newSubmit}>
<input type='text' name={'test1'} value={this.state.test1} onChange = {this.onChangeInput}
/>
<input type='text' name={'test2'} value={this.state.test2} onChange = {this.onChangeInput}
/>
<button type='submit'> submit </button>
</form>
</div>
)
}
}
export default ContactList;

Try this one, take notice on the callback function of setState
import React, { Component } from 'react';
class ContactList extends Component {
constructor(props){
super(props);
this.state = {
name: '',
test1:'',
test2:'',
newCtc:{},
ctcList:[],
arr: []
}
}
async componentDidMount() {
try{
const result = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await result.json()
this.setState({arr:data})
}catch(err){
console.log(err)
}
}
onChangeInput = (e)=>{
const target = e.target;
const name = target.name;
const value = target.value;
this.setState({
[name]: value
});
}
newSubmit = (e) =>{
e.preventDefault();
this.setState(Object.assign(this.state.newCtc,{test1:this.state.test1, test2:this.state.test2}), ()=>{
console.log('newctc', this.state.newCtc)
this.addContact();
});
}
addContact = ()=>{
let newCtcList = [...this.state.ctcList];
newCtcList.push({...this.state.newCtc});
console.log('newctc addcontact', this.state.newCtc);
console.log('newctclist',newCtcList);
this.setState({ ctcList: newCtcList }, ()=>{
console.log(this.state.ctcList);
this.clearInput();
});
};
clearInput = ()=>{
this.setState({test1:'',test2:''});
this.setState(Object.assign(this.state.newCtc,{test1:'', test2:''}));
};
render() {
return (
<div>
<input type = 'text' name = 'name' onChange = {this.onChangeInput}></input>
<form onSubmit = {this.newSubmit}>
<input type='text' name={'test1'} value={this.state.test1} onChange = {this.onChangeInput}
/>
<input type='text' name={'test2'} value={this.state.test2} onChange = {this.onChangeInput}
/>
<button type='submit'> submit </button>
</form>
</div>
)
}
}
export default ContactList;

Here a problematic line
// newCtc is empty => so Object.assign, simply returns {test1: 'some value', test2: // somevalue }
// this.setState then merges this into the array, so newCtc is not actually updated
// but the properties test1 and test2
this.setState(Object.assign(this.state.newCtc,{test1:this.state.test1, test2:this.state.test2}));
import React, { Component } from 'react';
import Contact from './Contact';
import TestData from './TestData';
class ContactList extends Component {
constructor(props){
super(props);
this.state = {
name: '',
test1:'',
test2:'',
newCtc:{},
ctcList:[],
arr: []
}
}
async componentDidMount() {
try{
const result = await fetch('https://jsonplaceholder.typicode.com/users')
const data = await result.json()
this.setState({arr:data})
}catch(err){
console.log(err)
}
}
onChangeInput = (e)=>{
const target = e.target;
const name = target.name;
const value = target.value;
console.log(value)
this.setState({
[name]: value
});
}
newSubmit = (e) =>{
e.preventDefault();
const ctcCopy = Object.assign({}, this.state.newCtc);
this.setState({newCtc: Object.assign(ctcCopy, {
test1: this.state.test1,
test2: this.state.test2,
})})
console.log(this.state.newCtc)
this.addContact();
this.clearInput();
console.log(this.state.newCtc);
}
// I would also copy this.state.newCtc
addContact = ()=>{
this.setState({ ctcList:[ ...this.state.ctcList, ...this.state.newCtc] });
console.log(this.state.ctcList);
};
clearInput = ()=>{
this.setState({test1:'',test2:''});
const ctcCopy = Object.assign({}, this.state.newCtc);
this.setState({newCtc: Object.assign(ctcCopy, {
test1: this.state.test1,
test2: this.state.test2,
})})
};
render() {
return (
<div>
<Contact firstName = {this.state.name} lastName='mcdaniel' phoneNumber = '585-721-3824' />
<input type = 'text' name = 'name' onChange = {this.onChangeInput}></input>
<TestData data={this.state.arr} />
<form onSubmit = {this.newSubmit}>
<input type='text' name={'test1'} value={this.state.test1} onChange = {this.onChangeInput}
/>
<input type='text' name={'test2'} value={this.state.test2} onChange = {this.onChangeInput}
/>
<button type='submit'> submit </button>
</form>
</div>
)
}
}
export default ContactList;

Related

Saving state to localStorage [duplicate]

I have no idea How to store the react js state into localstorage.
import React, { Component } from 'react'
import './App.css';
import { auth,createUserProfileDocument } from './firebase/firebase.utils'
import { TodoForm } from './components/TodoForm/TodoForm.component'
import {TodoList} from './components/TodoList/TodoList.component'
import {Footer} from './components/footer/footer.component'
import Header from '../src/components/header/header.component'
import {Redirect} from 'react-router-dom'
import {connect} from 'react-redux'
import {setCurrentUser} from './redux/user/user.actions'
export class App extends Component {
constructor(props) {
super(props)
this.input=React.createRef()
this.state = {
todos:[
{id:0, content:'Welcome Sir!',isCompleted:null},
]
}
}
todoDelete = (id) =>{
const todos = this.state.todos.filter(todo => {
return todo.id !== id
})
this.setState({
todos
})
}
toDoComplete = (id,isCompleted) =>{
console.log(isCompleted)
var todos = [...this.state.todos];
var index = todos.findIndex(obj => obj.id === id);
todos[index].isCompleted = !isCompleted;
this.setState({todos});
console.log(isCompleted)
}
addTODO = (todo) =>{
todo.id = Math.random()
todo.isCompleted = true
let todos = [...this.state.todos, todo]
this.setState({
todos
})
}
unsubscribeFromAuth = null;
componentDidMount() {
const { setCurrentUser } = this.props;
this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
userRef.onSnapshot(snapShot => {
setCurrentUser({
id: snapShot.id,
...snapShot.data()
});
});
}
setCurrentUser(userAuth);
});
}
componentWillUnmount() {
this.unsubscribeFromAuth();
}
render() {
return (
<div className='App'>
<Header />
<TodoForm addTODO={this.addTODO} />
<TodoList
todos={this.state.todos}
todoDelete={ this.todoDelete}
toDoComplete={ this.toDoComplete}
/>
<Footer/>
</div>
)
}
}
const mapStateToProps = ({ user }) => ({
currentUser: user.currentUser
});
const mapDispatchToProps = dispatch => ({
setCurrentUser: user => dispatch(setCurrentUser(user))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
in my input Form
import './TodoForm.style.css'
export class TodoForm extends Component {
constructor(props) {
super(props)
this.state = {
content : ''
}
}
handleChange = (e) =>{
this.setState({
content: e.target.value
})
}
handleSubmit =(e) =>{
e.preventDefault();
this.props.addTODO(this.state);
this.setState({
content: ''
})
}
render() {
return (
<div className='inputTask'>
<form onSubmit={ this.handleSubmit}>
<input
className="textBox"
type='text'
onChange={ this.handleChange}
value={this.state.content}
placeholder='what you want to do ...'
/>
</form>
</div>
)
}
}
export default TodoForm
I have no idea How to store the react js state into localstorage.
i searched on internet but unable to find the exact solution all the codes that i think is necessary post.
You can use reactLocalStorage to save any data in local storage
import {reactLocalStorage} from 'reactjs-localstorage';
reactLocalStorage.set('var', true);
reactLocalStorage.get('var', true);
reactLocalStorage.setObject('var', {'test': 'test'});
reactLocalStorage.getObject('var');
reactLocalStorage.remove('var');
reactLocalStorage.clear();
Read out the localStorage item in the componentDidMount callback. Simply read the item you want to get, check if it exists and parse it to a usable object, array or datatype that need. Then set the state with the results gotten from the storage.
And to store it, simply handle it in an event handler or helper method to update both the state and the localStorage item.
class ExampleComponent extends Component {
constructor() {
super();
this.state = {
something: {
foo: 'bar'
}
}
}
componentDidMount() {
const storedState = localStorage.getItem('state');
if (storedState !== null) {
const parsedState = JSON.parse(storedState);
this.setState({ something: parsedState });
}
}
clickHandler = (event) => {
const value = event.target.value;
const stringifiedValue = JSON.stringify(value);
localStorage.setItem('state', stringifiedValue);
this.setState({ something: value });
}
render() {
return (
<button onClick={clickHandler} value={this.state.something}>Click me</button>
);
}
}
Set data in localStorage
key-value pair :
localStorage.setItem('key_name',"value");
object
localStorage.setItem('key_name', JSON.stringify(object));
Remove data from localStorage
localStorage.removeItem('key_name');
Get data from localStorage
let data = localStorage.getItem('key_name');
object :
let data = JSON.parse(localStorage.getItem('key_name'));
clear localStorage (delete all data)
localStorage.clear();

React doesn't render form autofill suggestions

I'm using react to create a panel to add a new product. I've created a separate auto-complete class which is supposed to render an input element and a list of suggested autofill items underneath. The input element shows but not the autofill suggestions. Have a look at the code
Autofill class
import React, { Component } from "react";
import firebase from "../Firebase";
export default class AutoCompleteDistID extends Component {
constructor() {
super();
this.state = {
sellerName: [],
sellerId: [],
suggestions: [],
};
}
componentDidMount() {
var sellerRef = firebase.database().ref().child("Sellers");
sellerRef.once("value", (snapshot) => {
snapshot.forEach((childSnap) => {
var distrName = childSnap.val().sellerName;
var distrId = childSnap.val().sellerName.sellerId;
// var distrName = [{ name: data.sellerName }];
this.setState((prevState) => {
return {
sellerName: [...prevState.sellerName, distrName],
sellerId: [...prevState.sellerId, distrId],
suggestions: [...prevState.suggestions, distrName],
};
});
});
});
}
onTextChange = (e) => {
var sellerNames = [this.state.sellerName];
const value = e.target.value;
let newSuggestions = [];
if (value.length > 0) {
const regex = new RegExp(`^${value}`, "i");
newSuggestions = sellerNames.sort().filter((v) => regex.test(v));
}
this.setState(() => ({ newSuggestions }));
};
renderSuggestions() {
const newSuggestions = this.state.suggestions;
if (newSuggestions.length === 0) {
return null;
}
return (
<ul>
{newSuggestions.map((item) => (
<li>{item}</li>
))}
</ul>
);
}
render() {
return (
<div>
<input onChange={this.onTextChange} />
{this.renderSuggestions}
</div>
);
}
}
Main form
import React, { Component } from "react";
import firebase from "../Firebase";
import AutoCompleteDistID from "./AutoCompleteDistID";
export default class Products extends Component {
constructor() {
super();
this.state = {
description: "",
prodQty: "",
};
this.pushProduct = this.pushProduct.bind(this);
}
handleFormChange = (event) => {
const target = event.target;
const colName = target.name;
this.setState({
[colName]: event.target.value,
});
};
pushProduct() {
const userRef = firebase.database().ref().child("Users"); //Get reference to Users DB
const prodData = this.state;
userRef.push(prodData);
}
render() {
return (
<div>
<br />
<form style={{ border: "solid", borderWidth: "1px", width: "600px" }}>
<br />
<input
type="text"
value={this.state.prodQty}
placeholder="Available Quantity"
onChange={this.handleFormChange}
name="prodQty"
/>
<input
type="text"
value={this.state.description}
placeholder="Description"
onChange={this.handleFormChange}
name="description"
/>
<AutoCompleteDistID />
<br />
<br />
</form>
<button onClick={this.pushProduct} type="button">
Add Product
</button>
<br />
</div>
);
}
}
State variable is suggestions but you are setting newSuggestions.
onTextChange = (e) => {
var sellerNames = [this.state.sellerName];
const value = e.target.value;
let newSuggestions = [];
if (value.length > 0) {
const regex = new RegExp(`^${value}`, "i");
newSuggestions = sellerNames.sort().filter((v) => regex.test(v));
}
// HERE IS THE MISTAKE
this.setState(() => ({ suggestions: newSuggestions }));
};
In AutoCompleteDistID render method
render() {
return (
<div>
<input onChange={this.onTextChange} />
{this.renderSuggestions()}
</div>
);
}

How to Enter Text By User Input in React JS

I am trying to get the user to input data for my TODO App instead of picking up data from a predefined array.
Below is my Parent component
import React from "react"
import TodoItem from "./TodoItem"
import todosData from "./todosData"
class App extends React.Component {
constructor() {
super()
this.state = {
name: "",
todos: todosData
}
this.handleChange = this.handleChange.bind(this)
this.nameEnter = this.nameEnter.bind(this)
}
handleChange(id) {
this.setState(prevState => {
const updatedTodos = prevState.todos.map(item => {
if (item.id === id){
return {
...item,
completed: !item.completed
}
}
return item
})
return {
todos: updatedTodos
}
})
}
nameEnter(){
var name = this.name
console.log(name)
}
render() {
const todoItems = this.state.todos.map(item => <TodoItem key={item.id} item={item}
handleChange = {this.handleChange} nameEnter= {this.nameEnter}/>)
return (
<div className="todo-list">
{todoItems}
</div>
)
}
}
export default App
This one is the child component where I have added input fields
import React from "react"
function TodoItem(props) {
return (
<div className="todo-item">
<input
type = "checkbox"
checked = {props.item.completed}
onChange = { () => props.handleChange(props.item.id) }
/>
<input type = "text" name= "name" />
<p>{props.item.text}</p>
</div>
)
}
export default TodoItem
This is how my page looks. Instead of predefined text example:"GROCERRY SHOPPING", I want the user to enter text and it should be in place of that.
Ok so here it is
<input onChange={(e)=>handleChange(e)}/>
//react hooks
const [values,setValues] = useState({inputValue: 'predefined'});
handleChange = (e)=>{
setValues({...values,[e.target.name]: e.target.value})
}
//classes
handleChange = (e)=>{
this.setState({[e.target.name]:e.target.value});
}
this generic and can apply to a number of inputs, not just one
import React from "react"
class Form extends React.Component {
constructor() {
super()
this.state = {
name: ""
}
}
onChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
render() {
const {name} = this.state
return (
<input type="text" name="name" value={name} onChange={this.onChange}/>
)
}
}
export default Form
changeInputVal (ev, index) {
ev.persist();
const newArr = this.state.inputArrVal;
newArr[index]=ev.target.value;
this.setState({inputArrVal:newArr, currentPage:1});
}
you need to do something like that in TodoItem --
where --
1- inputArrVal:{} is object And
2- "this.changeInputVal(event, props.item.id)}/>"

Update value with user input

I have an input field that i would like to update that users first name when you click submit for that specific user. right now i have an alert in handleSubmit to just see if its working. and it is but i want it to update the actual users name.
Displays Users on separate cards. would like the edit button to work for each user.
class User extends Component {
constructor(props) {
super(props);
this.state = {
names: ''
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<div className='UserCard'>
<div className='UserCardTop'>
<form className='Submit' onSubmit={this.handleSubmit}>
<input
type="text"
name="names"
value={this.state.names}
ref={this.input}
onChange={this.handleChange} />
<input type="submit" value="Submit" />
</form>
<h3>{this.props.name} {this.props.last}</h3>
<div className='ImageContainer'>
<img alt="image" width="80" src={this.props.image} />
</div>
</div>
<div className='UserCardBottom'>
<h5>{this.props.email}</h5>
<h5>{this.props.cell}</h5>
<h5>{this.props.city}, {this.props.state}</h5>
</div>
</div>
)
}
}
export default User
App.js
import React, { Component } from "react";
import axios from "axios";
import User from './User'
import Filter from './Filter.js'
class App extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
searchTerm: '',
alphabetical: 'az'
};
this.handleChange = this.handleChange.bind(this);
this.handleFilter = this.handleFilter.bind(this);
}
componentDidMount() {
axios.get("https://randomuser.me/api/?page=3&results=10&seed=abc")
.then(response => {
console.log(response.data.results);
this.setState({ users: response.data.results });
})
.catch(error => {
console.log(error);
});
}
handleFilter(filterInput) {
this.setState(filterInput)
}
handleChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
let sortedUsers;
if (this.state.alphabetical === "az") {
console.log("sorted");
sortedUsers = this.state.users.sort((a, b) =>
a.name.first > b.name.first ? 1 : -1
);
}
let filteredUsers = sortedUsers;
if (this.state.searchTerm)
filteredUsers = this.state.users.filter(u =>
u.name.first.startsWith(this.state.searchTerm) || u.name.last.startsWith(this.state.searchTerm)
);
const userNames = filteredUsers.map(u => {
return <User
key={u.email}
name={u.name.first}
last={u.name.last}
image={u.picture.large}
email={u.email}
city={u.location.city}
state={u.location.state}
cell={u.cell}
/>;
});
return (
<div>
<Filter
searchTerm={this.state.searchTerm}
onFilter={this.handleFilter}
></Filter>
<select
name="alphabetical"
value={this.state.alphabetical}
onChange={this.handleChange}>
<option value="az">
A to Z
</option>
<option value="za">Z to A</option>
</select>
{userNames}
</div>
);
}
}
export default App
A simple solution would be to add an onChangeFirst callback prop to your User component, which would be invoked with the new first name when handleSubmit() is called:
User.js
handleSubmit(event) {
event.preventDefault();
if(this.props.onChangeFirst) {
/* Pass this users state (with names data) to onChange callback */
this.props.onChangeFirst(this.state.names);
}
}
The onChangeFirst callback prop would be "wired up" to the App component so that when it is called (from inside User.js), the corresponding user object (in App.js) is updated with the newFirstName. You could add the onChangeUserFirstName() function as shown below, which updates the first field of the user object in the App components state:
App.js
/* Helper function that updates first name state for matching user */
const onChangeUserFirstName = (user, newFirstName) => {
/* Updates state with newly mapped users to new array, where first name
if updated to that supplied in changes.names for existing user match */
this.setState({ users : this.state.users.map(u => {
return (u === user) ? { ...u, first : newFirstName } : u;
});
});
}
const userNames = filteredUsers.map(u => {
/* Add (newFirstName) => onChangeUserFirstName(u, newFirstName) */
return <User
onChangeFirst={ (newFirstName) => onChangeUserFirstName(u, newFirstName) }
key={u.email}
name={u.name.first}
last={u.name.last}
image={u.picture.large}
email={u.email}
city={u.location.city}
state={u.location.state}
cell={u.cell}
/>;
});

handleRemove function for Todo List app with an array of objects

So I am making this app super simple, however I can't get my handleRemove to work properly. filteredTodos comes out to be a list of all the same todos. This is my code.
I have tried even looking at other solutions online but for some reason this filter function in handleRemove does not filter anything out of the state.
import React, { Component } from 'react';
class Main extends Component {
constructor(props){
super(props);
this.state = {
todos: [],
inputValue: '',
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
handleChange = (e) => {
e.preventDefault();
this.setState({
inputValue: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
const newTodo = this.state.inputValue;
if (this.state.inputValue === ''){
alert('Please Enter a Todo!');
} else {
this.setState((prevState) => ({
todos: [...prevState.todos,
{
message: newTodo,
id: this.state.todos.length
}
]
}));
this.setState({inputValue:''});
}
}
handleRemove (id) {
const filteredTodos = this.state.todos.filter(todo => todo.id !== id);
this.setState({
todos: filteredTodos
});
console.log(filteredTodos);
}
render(){
const mappedTodos = this.state.todos.map((item, i) =>
<div key={i} id={this.state.todos[i].id}>
{item.message} <button type='submit' onClick={this.handleRemove}>X</button>
</div>
)
return(
<div className='main-page'>
<div className='input'>
<input type='text' placeholder='Enter Your Todo' value={this.state.inputValue} onChange={this.handleChange} />
<button type='submit' onClick={this.handleSubmit}>Add</button>
</div>
<div className='todos'>
{mappedTodos}
</div>
</div>
)
}
}
export default Main;
Your handleRemove function requires an id you can see it by the value in the round brackets
handleRemove (id)
to fix the problem you just have to pass the parameter just like this:
const mappedTodos = this.state.todos.map((item, i) =>
<div key={i} id={this.state.todos[i].id}>
{item.message} <button type='submit' onClick={this.handleRemove(this.state.todos[i].id)}>X</button>
</div>
)

Categories