I am new to react. This errors occurs. Am I using too many useState()? I have been looking at the problems many times, I don't know what happen
The Error Message
-Uncaught Error: Too many re-renders. React limits the number of renders to prevent an
infinite loop.
The above error occurred in the <App> component:
at App (http://localhost:3000/static/js/bundle.js:261:82)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
My AddMember Component.AddMember.js.Am I using too many useState here
import React, { useState } from "react";
import "../src/css/AddMember.css";
const AddMember = (props) => {
const [nameofmovie, setnameofmovie] = useState("");
const [moviepic, setmoviepic] = useState("");
const [leadActor, setleadActor] = useState("");
const [rating, setRating] = useState("");
function onChangeName(event) {
setnameofmovie(event.target.value);
}
function onChangeImage(event) {
setmoviepic(event.target.value);
}
function onChangeActor(event) {
setleadActor(event.target.value.split(","));
}
function onChangeRating(event) {
setRating(event.target.value);
}
const transferValue = (event) => {
event.preventDefault();
const val = {
name: nameofmovie,
"picture of image": moviepic,
"lead actor": leadActor,
rating: rating,
};
props.onSubmitHandler(val);
clearState();
};
const clearState = () => {
setnameofmovie("");
setmoviepic("");
setleadActor("");
setRating("");
};
return (
<div>
<div id="topFormLayerOne">
<form>
<div id="secondFormLayerTwo">
<label id="labelTwo">Please key in the Id</label>
<input
id="inputThree"
type="text"
maxLength="10"
placeholder="Please key in the Id"
></input>
<label id="labelFour">Movie Names</label>
<input
onChange={onChangeName}
id="inputFour"
type="text"
maxLength="100"
placeholder="Movies Names"
name="moviesName"
></input>
<label id="labelFive">Picture of Movies</label>
<input
onChange={onChangeImage}
id="inputFive"
type="file"
maxLength="100"
placeholder="Name of Images"
name="imageName"
></input>
<label id="labelSix">Lead Actor Names</label>
<input
onChange={onChangeActor}
id="inputSix"
type="text"
maxLength="500"
placeholder="Name of Actor"
name="actorName"
></input>
<label id="labelSeven">Rating</label>
<input
onChange={onChangeRating}
id="inputSeven"
type="text"
maxLength="10"
placeholder="Rating"
name="movieRating"
></input>
<button onClick={transferValue} id="submitButton">
Submit
</button>
<button id="removeButton">Remove Movie</button>
</div>
</form>
</div>
</div>
);
};
export default AddMember;
My Member Component.Member.js
import React from "react";
function Members({data}) {
const tableRows = (data) => (data.map((info) => {
return(
<tr key={info.id}>
<td>{info.id}</td>
<td>{info.name}</td>
<td><img src={info["picture of image"]} alt=""></img><
<td>
{info["lead actor"]}
</td>
<td>{info.rating}</td>
</tr>
)
}))
return (
<div>
<table className="table table-stripped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Image</th>
<th>Actors</th>
<th>Rating</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table></div>
);
}
export default Members;
My App Component.My App.js
import dataMovielist from '../src/data/data.json';
import Members from './Members';
import AddMember from './AddMember';
import {useState} from 'react';
function App() {
const [datalist, setdatalist] = useState(dataMovielist);
const onSubmitHandler = ((newHobbies)=>{
setdatalist((oldHobbies)=>[newHobbies,...oldHobbies])
})
return (
<div className="App">
<AddMember onSubmitHandler = {onSubmitHandler()} />
<Members data={datalist} />
</div>
);
}
export default App;
I don't know what happen. Can you help me solve it
I think it's this line:
<AddMember onSubmitHandler = {onSubmitHandler()} />
You probably meant to write <AddMember onSubmitHandler={onSubmitHandler} /> The parentheses are causing the function to be invoked immediately as opposed to onSubmit. This is likely triggering a chain reaction.
Also, you want to change this line:
<tbody>{tableRows}</tbody>
to
<tbody>{tableRows(data)}</tbody>
to avoid "Functions are not valid a React child" error.
Related
I am stuck with a problem , I don't know how to do it. I want to display selected gifs , when I search its work properly , when I click on any gifs only this gifs is selected and display when I click on post button..
In This problem if anyone have any query please free feel to ask
App.js
This is the App.js file only single file I wrote my all code.
import "./App.css";
import { useEffect, useState } from "react";
import Axios from 'axios';
function App() {
const Api_key="QlYtlejKAxArXXXXXXXXXXXXXXXXX";
const Base_Url = "http://api.giphy.com/v1/gifs/search";
const [searchText,setSearchText] = useState("");
const [searchGif,setSearchGif] = useState("");
const [addText,setAddText] = useState([]);
const [gifs,setGifs] = useState([]);
const postValue = ()=>{
const addData = {
id:Date.now(),
name:searchText
}
console.log(addData);
setAddText([...addText,addData])
setSearchText("");
// Add Gifs
gifResponse();
}
const gifResponse = async()=>{
const response = await Axios.get(`${Base_Url}?api_key=${Api_key}&q=${searchGif}`)
// const res = await response.json();
setGifs(response.data.data);
console.log(response.data.data)
}
return (
<div className="App">
<div className="container">
<textarea
type="text"
className="form-control shadow-none mt-3"
rows="15"
cols="50"
placeholder="Write Something Here..."
value={searchText}
onChange={(e)=>setSearchText(e.target.value)}
/>
<div class="input-group mb-3 mt-2">
<input
type="text"
class="form-control shadow-none"
placeholder="Search Gif..."
aria-label="Recipient's username"
aria-describedby="basic-addon2"
value={searchGif}
onChange={(e)=>setSearchGif(e.target.value)}
/>
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2" onClick={postValue}>
POST
</span>
</div>
</div>
{
addText.map((add,index)=>{
return <h4 key={index}>{add.name}</h4>
})
}
{
gifs.map((gif)=>{
return <img src={gif.images.fixed_height.url} />
})
}
</div>
</div>
);
}
export default App;
import { useState } from "react";
import "./ExpenseForm.css";
function ExpenseForm() {
const [enteredTitel, setEnteredTitle] = useState("");
const [enteredAmount, setEnteredAmount] = useState("");
const [enteredDate, setEnteredDate] = useState("");
const titleChangeHandler = (event) => {
setEnteredTitle(event.target.value);
};
const amountChangeHandler = (event) => {
setEnteredAmount(event.target.value);
};
const dateChangeHandler = (event) => {
setEnteredDate(event.target.value);
};
const submitHandler = (event) => {
event.preventDefault();
const expenseData = {
title: enteredTitel,
amount: enteredAmount,
date: new Date(enteredDate),
};
console.log(expenseData);
};
return (
<form onSubmit={submitHandler}>
<div className="new-expense__controls">
<div className="new-expense__control">
<label>Title</label>
<input type="text" onChange={titleChangeHandler} />
</div>
<div className="new-expense__control">
<label>Amount</label>
<input
type="number"
min="0.01"
step="0.01"
onChange={amountChangeHandler}
/>
</div>
<div className="new-expense__control">
<label>Date</label>
<input
type="date"
min="2019-01-01"
max="2022-12-12"
onChange={dateChangeHandler}
/>
</div>
</div>
<div className="new-expense__actions">
<button type="submit">Add Expense</button>
</div>
</form>
);
}
export default ExpenseForm;
Im following a react udemy course. the error in title pops up in the browser consol when i try to use the form. when i looked it up this error usualy comes up when a form is in a form but there arnt any others in my code any idea why thi is happening.
It randomly started doing this and I am not sure why tho. I have two modals (these are named differently) that are exactly the same but only one is working. The modal I am using is the React-Modal library. The first one works just fine on the home page but the second doesn't at all on an edit details page.
What I did notice is that there is a div placed with an Id of __Next on the home page that is working that places the content of the modal inside but that same exact div does not show up on the other page for the same modal to work.
Below are the two components I am working with and its parent component that houses both
Parent:
import styles from './homeheader.module.css';
import { useRouter } from 'next/router';
import { useState } from 'react';
import NewInvoice from '../invoice/modal/NewInvoice';
import Link from 'next/link';
import { getDatabase, ref, remove } from "firebase/database";
import { database } from '../firebase/firebase';
import EditInvoice from '../invoice/modal/EditInvoice';
export default function HomeHeader(props) {
const [newInvoiceModalIsOpen, setNewInvoiceOpen] = useState(false);
const [editInvoiceModalIsOpen, setEditInvoiceOpen] = useState(false);
const router = useRouter();
const pathName = router.pathname;
const { data, count, id, detail } = props;
function openNewInvoiceModalHandler() {
setNewInvoiceOpen(true)
}
function closeNewInvoiceModalHandler() {
setNewInvoiceOpen(false)
}
function openEditInvoiceModalHandler() {
setEditInvoiceOpen(true)
}
function closeEditInvoiceModalHandler() {
console.log(data)
setEditInvoiceOpen(false)
}
function deleteInvoiceHandler() {
console.log('delete')
console.log(id)
const db = database;
remove(ref(db, 'invoices/' + id))
}
function markAsPaidInvoiceHandler() {
console.log('paid')
}
if (pathName === '/detail/[id]') {
return (
<>
<div className={styles.headerwrapper}>
<Link href="/">
<a>Go back</a>
</Link>
{/* <p>{detail.data.status}</p> */}
<div>
<button onClick={openEditInvoiceModalHandler}>Edit</button>
<button onClick={deleteInvoiceHandler}>Delete</button>
<button onClick={markAsPaidInvoiceHandler}>Mark as Paid</button>
</div>
</div>
<EditInvoice isOpen={editInvoiceModalIsOpen} closeModal={closeEditInvoiceModalHandler} details={detail}/>
</>
)
}
return (
<div className={styles.headerwrapper}>
<div className={styles.leftside}>
<h1 className={styles.header}>Invoices</h1>
<p className={styles.text}>There are {count} total invoices</p>
</div>
<div className="right-side">
<select className={styles.filter} id="filter" placeholder="Filter by status">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
<button className={styles.button} onClick={openNewInvoiceModalHandler}>New Invoice</button>
</div>
<NewInvoice isOpen={newInvoiceModalIsOpen} closeModal={closeNewInvoiceModalHandler} count={count}/>
</div>
)
}
Child modal component that IS WORKING:
import { useForm } from 'react-hook-form';
import ReactModal from 'react-modal';
import { database } from '../../firebase/firebase';
import { ref, set } from "firebase/database";
import styles from './newinvoice.module.css'
// ReactModal.setAppElement("#__next")
export default function NewInvoice (props) {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
function onSubmit(data) {
const randGen = Math.floor(Math.random() * 9999999);
data.id = randGen;
const db = database;
set(ref(db, '/invoices/' + randGen), {
data: data
})
setTimeout(() => {
window.location.reload(true)
}, 500)
props.closeModal();
}
return (
<>
<ReactModal isOpen={props.isOpen}>
<h1>New Invoice</h1>
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<label>Street Address</label>
<input {...register("senderAddress.street")} />
<label>City</label>
<input {...register("senderAddress.city")} />
<label>Postal Code</label>
<input {...register("senderAddress.postCode")} />
<label>Country</label>
<input {...register("senderAddress.country")} />
<label>Client"s Name</label>
<input {...register("clientName")} />
<label>Client"s Email</label>
<input {...register("clientEmail")} />
<label>Street Address</label>
<input {...register("clientAddress.street")} />
<label>City</label>
<input {...register("clientAddress.city")} />
<label>Postal Code</label>
<input {...register("clientAddress.postCode")} />
<label>Country</label>
<input {...register("clientAddress.country")} />
<label>Invoice Date</label>
<input {...register("createdAt")} />
<label>Payment Terms</label>
<input {...register("paymentTerms")} />
<label>Project Description</label>
<input {...register("description")} />
{/* //Item list goes here */}
<input {...register("items")} />
<input type="submit" placeholder="Submit"/>
</form>
<button onClick={props.closeModal}>Close</button>
</ReactModal>
</>
)
}
Child component that is NOT WORKING:
import { useForm } from 'react-hook-form';
import ReactModal from 'react-modal';
import { database } from '../../firebase/firebase';
import { ref, set } from "firebase/database";
import { useRouter } from 'next/router';
import styles from './newinvoice.module.css'
import { useEffect, useState } from 'react';
ReactModal.setAppElement("#react-modals")
export default function EditInvoice(props) {
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const [formData, setFormData] = useState();
const { isOpen, closeModal, detail } = props;
const router = useRouter();
const id = router.query.id;
const dbLink = `https://invoice-app-3fa85-default-rtdb.firebaseio.com/invoices/${id}.json`;
function onSubmit(data) {
const db = database;
set(ref(db, '/invoices/' + id), {
data: data
})
setTimeout(() => {
window.location.reload(true)
}, 500)
props.closeModal();
}
// function onSubmit(data) {
// console.log(data)
// }
useEffect(() => {
// fectchData();
console.log(formData)
})
const fectchData = async () => {
try {
const res = await fetch(dbLink);
const json = await res.json();
setFormData(json)
} catch (error) {
console.log(error)
}
}
if (!formData) {
console.log('not working')
return <p>Loading....</p>
}
return (
<>
<ReactModal isOpen={true} portalClassName="editInvoiceModal" parentSelector={() => document.querySelector('#react-modals')}>
<h1>Edit Invoice </h1>
<form className={styles.form} onSubmit={handleSubmit(onSubmit)}>
<label>Street Address</label>
<input {...register("senderAddress.street")} defaultValue={detail.senderAddress.street}/>
{/* <label>City</label>
<input {...register("senderAddress.city")} defaultValue={formData.senderAddress.city}/>
<label>Postal Code</label>
<input {...register("senderAddress.postCode")} defaultValue={formData.senderAddress.postCode}/>
<label>Country</label>
<input {...register("senderAddress.country")} defaultValue={formData.senderAddress.country}/>
<label>Client"s Name</label>
<input {...register("clientName")} defaultValue={formData.clientName}/>
<label>Client"s Email</label>
<input {...register("clientEmail")} defaultValue={formData.clientEmail}/>
<label>Street Address</label>
<input {...register("clientAddress.street")} defaultValue={formData.clientAddress.street}/>
<label>City</label>
<input {...register("clientAddress.city")} defaultValue={formData.clientAddress.city}/>
<label>Postal Code</label>
<input {...register("clientAddress.postCode")} defaultValue={formData.clientAddress.postCode}/>
<label>Country</label>
<input {...register("clientAddress.country")} defaultValue={formData.clientAddress.country}/>
<label>Invoice Date</label>
<input {...register("createdAt")} defaultValue={formData.createdAt}/>
<label>Payment Terms</label>
<input {...register("paymentTerms")} defaultValue={formData.paymentTerms}/>
<label>Project Description</label>
<input {...register("description")} defaultValue={formData.description}/>
{/* //Item list goes here */}
<input type="submit" placeholder="Submit"/>
</form>
<button onClick={closeModal}>Close</button>
</ReactModal>
</>
)
}
It may be sloppy code as of now and was working to clean it up a lot more until I noticed this issue.
In your parent, try adding a placeholder.
<div id="react-modals" />
Your react modal seems to be looking for a div with the #react-modals id.
I am new to ReactJS and building one simple application using few components like UserForm, UserGrid and App.
UserForm displays simple textbox and button like below.
and when user input some text inside textbox and hit the save button it will display data in UserGrid component as per the screenshot.
but i can't figure it out how edit will work ? like when i hit the edit it will fetch the information from the grid and fill the textbox so i can update the data, can someone please help me on this ? how can i achieve this ?
below is my code
UserForm.js
import React,{createRef} from 'react';
const UserForm = (props) =>{
const username = createRef();
const saveUser = () =>{
debugger
if(username.current.value !== ''){
props.handleSubmit(username.current.value);
username.current.value='';
username.current.focus();
}
}
return(
<div className="row">
<div className="col-md-6">
<div className="form-group">
<input type="text" className="form-control" placeholder="Username" ref={username} />
</div>
</div>
<div className="col-md-12">
<button className="btn btn-primary" onClick={saveUser}>Save</button>
</div>
</div>
)
}
export default UserForm;
UserGrid.js
import React from 'react';
const UserGrid = (props) =>{
debugger
return(
<div className="row">
<div className="col-md-12">
<table className="table">
<tr>
<th>
Username
</th>
<th>
</th>
</tr>
{
props.list.map(item =>
<tr>
<td>
{item}
</td>
<td>
<button>Edit</button>
<button>Delete</button>
</td>
</tr>
)
}
</table>
</div>
</div>
)
}
export default UserGrid;
App.js
import React,{useState} from 'react';
import UserForm from './UserForm';
import UserGrid from './UserGrid';
function App() {
const [list, setList] = useState([]);
const handleSubmit = (username) =>{
setList([...list,username]);
}
return (
<div className="App">
<UserForm handleSubmit={handleSubmit}></UserForm>
<UserGrid list={list}></UserGrid>
</div>
);
}
export default App;
You have to bring your edit state up to App component rather than using ref in the child component. Just like you have handleSubmit in App.js have a handleEdit function and pass that function to UserGrid.
function App() {
const [list, setList] = useState([]);
const [name, setName] = useState('');
const [editIndex, setEditIndex] = useState(null);
const handleSubmit = () => {
if(editIndex) {
setList([...list.slice(0, index), name, ...list.slice(index+1)])
setEditIndex(null)
} else {
setList([...list, name]);
}
setName('')
}
return (
<div className="App">
<UserForm name={name} setName={setName} handleSubmit={handleSubmit}></UserForm>
<UserGrid setEditIndex={setEditIndex} list={list}></UserGrid>
</div>
);
}
UserForm.js
import React,{createRef} from 'react';
const UserForm = ({name, setName}) =>{
const saveUser = () =>{
debugger
if(name !== ''){
props.handleSubmit();
}
}
return(
<div className="row">
<div className="col-md-6">
<div className="form-group">
<input type="text" className="form-control" placeholder="Username" value={name} onChange={(e) => setName(e.target.value)} />
</div>
</div>
<div className="col-md-12">
<button className="btn btn-primary" onClick={saveUser}>Save</button>
</div>
</div>
)
}
export default UserForm;
To support edit:
{
props.list.map((item, index) =>
<tr>
<td>
{item}
</td>
<td>
<button onClick={setEditIndex(index)}>Edit</button>
<button>Delete</button>
</td>
</tr>
)
}
This is working example while i am using your code.
Nothing special in App.js. You can take a look a logic.
App.js
import React, { useState } from "react";
import UserForm from "./UserForm";
import UserGrid from "./UserGrid";
function App() {
const [list, setList] = useState([]);
const handleSubmit = username => {
setList([...list, username]);
};
const editList = item => {
setList(
list.map(l => ({
...l,
username: l.id === item.id && item.newValue ? item.newValue : l.username
}))
);
};
const deleteList = id => {
setList(list.filter(l => l.id !== id));
};
return (
<div className="App">
<UserForm handleSubmit={handleSubmit}></UserForm>
<UserGrid
list={list}
editList={editList}
deleteList={deleteList}
></UserGrid>
</div>
);
}
export default App;
This is UserForm Component. I think you will have problems, if you dont have someting like ID, cuz if you have lists with same names, your delete and edit function will work wrong.
UseForm.js
import React, { createRef } from "react";
const UserForm = ({ handleSubmit }) => {
const username = createRef();
const saveUser = () => {
if (username.current.value !== "") {
const randomId = () => "_" + Math.random().toString(36).substr(2, 9);
handleSubmit({ username: username.current.value, id: randomId() });
username.current.value = "";
username.current.focus();
}
};
return (
<div className="row">
<div className="col-md-6">
<div className="form-group">
<input
type="text"
className="form-control"
placeholder="Username"
ref={username}
/>
</div>
</div>
<div className="col-md-12">
<button className="btn btn-primary" onClick={saveUser}>
Save
</button>
</div>
</div>
);
};
export default UserForm;
And this is UserGrid component. I hope you will undarstand the code. If you have questions, go ahead.
UseGrid.js
import React, { useState } from "react";
const UserGrid = ({ list, editList, deleteList }) => {
const [isEditable, setIsEditable] = useState(false);
const [value, setValue] = useState("");
return (
<div className="row">
<div className="col-md-12">
<table className="table">
<tr>
<th>Username</th>
<th></th>
</tr>
{list.map(item => (
<tr>
<td>{item.username}</td>
{isEditable ? (
<>
<td>
<input
type="text"
className="form-control"
placeholder="Username"
onChange={e => setValue(e.target.value)}
/>
</td>
<button onClick={() => setIsEditable(false)}>CANCEL</button>
</>
) : null}
<td>
<button
onClick={() => {
editList({
id: item.id,
username: item.username,
newValue: value
});
setIsEditable(true);
}}
>
Edit
</button>
<button onClick={() => deleteList(item.id)}>Delete</button>
</td>
</tr>
))}
</table>
</div>
</div>
);
};
export default UserGrid;
I'm trying to get a date as user input through a controlled component but always running into this error "TypeError: Cannot read property 'name' of undefined". This is the piece of code that's causing the error. I'm using the react-datepicker module to get the Date input as when I try to use the HTML input type="date" i'm unable to disable previousdates.
import React, {Fragment,useState,useEffect} from 'react';
import {Link,withRouter} from 'react-router-dom';
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {addTask} from '../../actions/task';
import { addDays } from 'date-fns';
const TaskForm = ({addTask}) => {
const [formData,setFormData] = useState({
description:'',
due_at:'',
toBeReminded:''
})
const onSubmit = e => {
e.preventDefault();
addTask(formData);
}
const onChange = e=>setFormData({...formData, [e.target.name]:e.target.value})
const {description,due_at} = formData;
return (
<Fragment>
<h1 className="large text-primary">
New Task
</h1>
<form className="form my-1" onSubmit={e=>onSubmit(e)}>
<div className="form-group">
<label htmlFor="descr">Description:</label><br/>
<input type="text" id="descr" placeholder="Task Description" name="description" value={description} onChange={e=> onChange(e)}/>
</div>
<div className="form-group">
<label htmlFor="due_date">Due Date for Task:</label><br></br>
<DatePicker id="due_date" minDate={addDays(new Date(), 1)} id="due_date" name="due_at" value={due_at} onChange={e=> onChange(e)} />
</div>
<div className="form-group">
<label htmlFor="reminder">Set Reminder:</label><br></br>
<input type="radio" id="yes" name="toBeReminded" value="true" onClick={e=> onChange(e)}/>
<label htmlFor="yes">Yes</label><br/>
<input type="radio" id="no" name="toBeReminded" value="false" onClick={e=> onChange(e)}/>
<label htmlFor="no">No</label><br></br>
</div>
<input type="submit" className="btn btn-dark my-1" value="Submit" />
<Link className="btn btn-light my-1" to="/tasks">Go Back</Link>
</form>
</Fragment>
)
}
TaskForm.propTypes = {
addTask:PropTypes.func.isRequired
}
export default connect(null,{addTask})(TaskForm);
Looking at the docs for react-datepicker, it doesn't look like its onChange receives an event, but the date.
You should use a separate handler for the date change handler since they expect different signatures.
const onChange = e => setFormData({...formData, [e.target.name]:e.target.value})
const onDateChange = date => setFormData({...formData, due_at: date})
There's a lot of other solutions that would work if you really want to stick to one change handler, but I recommend just creating two like above.
But.. you could do something like this (I don't really recommend this):
const onChange = e => {
if (typeof e === 'object') {
setFormData({...formData, [e.target.name]:e.target.value})
} else {
setFormData({...formData, due_at: e})
}
}
Or since you're declaring new inline functions already (its unnecessary by the way, just do onChange={onChange} unless you use the following approach) you could do this:
const onChange = (name, value) => setFormData({...formData, [e.target.name]:e.target.value})
// Regular inputs
onChange={e => onChange('input name', e.target.value)}
// Date input
onChange={date => onChange('input name', date)}
The bottom line is: you have to pay attention to what onChange is expected to receive. It will differ depending on the input type or the library implementation.