How To render properly a component in react useEffect and firebase - reactjs

I am trying to get instantly data from my Firebase with onSnapshot and it is working.
But the input field got the same amount of data in the Firebase as [object object],[object object] if I have two data in the Firestore. If I want to add data then when I click on the input field, the page becomes white.
I can't add new data this way.
Any help, please?
codesandbox.io ==> https://codesandbox.io/s/long-bush-sjkjnq?file=/src/Body/AppBody.jsx
function AppBody() {
const [reservation, setReservation] = useState([]);
useEffect(()=>{
db.collection('reservations')
.orderBy('timestamp', 'asc')
.onSnapshot(snapshot =>(
setReservation(snapshot.docs.map(doc =>({
id: doc.id,
data: doc.data()
})))
))
},[])
const handleClick = ()=>{
if(!reservation){
return;
}
db.collection('reservations').add({
title: reservation,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
})
setReservation("");
}
return (
<div className="appBody" >
<div className="appBody__left">
<h3>Reservations: </h3>
<div className="reservationCard">
{reservation.map(({id, data: {title}}) =>{
return <ReservationCardItem
key={id}
id={id}
title={title}
Icon={CloseIcon} />
})}
</div>
<div className="reservationInput">
<input type="text" placeholder="reservation name" value={reservation}
onChange={(e)=>setReservation(e.target.value)} />
<button onClick={handleClick} >Add</button>
</div>
</div>
<div className="vertical__line"></div>
<div className="appBody__right">
<h3>Menus: </h3>
<div className="menu__card">
<div className="menuCard__person">
<h4>Selena gomez</h4>
<CloseIcon />
</div>
<div className="menucard__menu">
<ReservationCardItem title="Selena" Icon={CloseIcon} />
<ReservationCardItem title="Selena" Icon={CloseIcon} />
</div>
<div className="menuCard__input">
<input type="text" placeholder="add Menu item" />
<button>Add</button>
</div>
</div>
</div>
</div>
)
}
export default AppBody

I created another piece of state (like a copy), so that I didn't use the initial state directly. And it worked.
I don't know if it was the better solution, but it worked fine :)

Related

How to add no of fields dynamically by taking input from user react

I want to add the input no of fields given by the user when clicking on submit button.How to do this in react functional component.
screenshot:
I have an input field,when any user input on that field and submit,according to the input given by the user the no fields will be created.like in above screenshot if a user gives input 6 then 6 fields will be added
I am trying in this way,
import React, { useState } from 'react'
import cal from './image/bgimg.jpg'
function Home() {
const [state,setState]=useState({
semester:'',
credit:'',
sgpa:''
})
const [noOfSem,setNoOfSem]=useState()
const handleChange=(e)=>{
setState({...state,[e.target.name]:e.target.value})
}
const handleClick=()=>{
console.log('hyy',state.semester)
setNoOfSem([state.semester])
}
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<img src={cal} alt="" className='imgcal img-fluid' />
</div>
<div className="col-md-6">
<div className="col-md">
<div className="form1">
<input type="number" value={state.semester} name='semester' onChange={handleChange} placeholder='Enter Total Semester' />
<button type="button" class="btn btn-success" onClick={handleClick}>Submit</button>
<div className="form2">
{noOfSem?.map((item,index)=>
<>
<input type="text" placeholder={`Enter your Semester ${index+1} credit`} key={index}/>
</>
)}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default Home
thanks......
I think there's a few changes you can make to improve the code and get it working.
Firstly, I would avoid storing your number of semesters in both the state.semester and noOfSem state, as it means you have to update both of them to keep them in sync.
Given that your component only needs to know the number of semesters when the user presses Submit, you can remove the handleChangeCall and instead only access the value upon submit.
It is also good practice to make use of the <form onSubmit={}> and <input type='submit'> elements, to handle form submission. Instead of using the onClick event from a regular <button>. Some info here.
When using the form, you can then access the value of the semester input directly by storing a reference to it using useRef.
Then in order to iterate over the number of semester, you can construct a new Array to map over. One caveat here is that you have to call the array fill method.
See solution here:
import React, { useState, useRef } from "react";
function Home() {
const [state, setState] = useState({
semester: '',
credit: "",
sgpa: ""
});
const semesterInputRef = useRef();
const handleForm1Submit = (e) => {
e.preventDefault();
if (semesterInputRef?.current.value) {
setState({ ...state, semester: Number(semesterInputRef.current.value) });
}
};
return (
<div className="container">
<div className="row">
<div className="col-md-6">
<div className="col-md">
<form className="form1" onSubmit={handleForm1Submit}>
<input
type="number"
name="semester"
ref={semesterInputRef}
placeholder="Enter Total Semester"
></input>
<input type="submit" className="btn btn-success"></input>
</form>
<form className="form2">
{state.semester &&
Array(state.semester).fill().map((_item, index) => (
<input
key={index}
type="text"
placeholder={`Enter your Semester ${index + 1} credit`}
></input>
))}
</form>
</div>
</div>
</div>
</div>
);
}
export default Home;
I've also created a code sandbox to show that this works as expected, here.

ReactJs TypeError: handleChange is not a function

I am trying to debug this error using console.log() to see where the error occurs. I am new to ReactJs, and this code comes from a tutorial. My app displays without error on the localhost:3000, until I enter a value, and then I get the "TypeError".
console.log(workworkwork) is logged in the console.
However, console.log(stuffystuff)is never executed.
Does this mean that the error occurs between my two console.logs()?
Main.js
}
const Main = () => {
const {formData, handleChange, sendTransaction} =
useContext; {TransactionContext}
console.log("workworkwork")
const handleSubmit = async (e) => {
const { addressTo, amount } = formData
e.preventDefault()
if (!addressTo || !amount) return
sendTransaction()
console.log("stuffystuff")
}
return (
<div className= {style.wrapper}>
<div className={style.content}>
<div className={style.formHeader}>
<div>Swap</div>
<div>
<RiSettings3Fill />
</div>
</div>
<div className={style.transferPropContainer}>
<input
type='text'
className={style.transferPropInput}
placeholder='0.0'
pattern='^[0-9]*[.,]?[0-9]*$'
onChange={e => handleChange(e, 'amount')}
/>
<div className={style.currencySelector}>
<div className={style.currencySelectorContent}>
<div className={style.currencySelectorIcon}>
<Image src={ethLogo} alt='eth logo' height={20} width={20} />
</div>
<div className={style.currencySelectorTicker}>ETH</div>
<AiOutlineDown className={style.currencySelectorArrow} />
</div>
</div>
</div>
<div className={style.transferPropContainer}>
<input
type='text'
className={style.transferPropInput}
placeholder='0x...'
onChange={e => handleChange(e, 'addressTo')}
/>
<div className={style.currencySelector}></div>
</div>
<div onClick={e => handleSubmit(e)} className={style.confirmButton}>
Confirm
</div>
</div>
</div>
)
}
export default Main

REACT JS FIREBASE FIRESTORE- how can i update my field in a document?

here is my manageexam.jsx file
this is where the update happen when i click the manage button on the table. i want to update a specific document id (3BelYq7lMxRNrWKknCRK- this is a sample of my document id but ofcourse there will be a lot of document id when i will add more inside the collection.) but i want to update the fields without manually adding the document Id that i want to update.
const ManageExam = () => {
const [description,setDesc]=useState("")
const [title,setTitle]=useState("")
function handleUpdate(e){
e.preventDefault();
const examcollref = doc(db,'Exams' "3BelYq7lMxRNrWKknCRK")
updateDoc(examcollref,{
title:title,
description:description
} ).then(response => {
alert("updated")
}).catch(error =>{
console.log(error.message)
})
}
return (
<div className="manageExam">
<Sidebar/>
<div className="manageExamContainer">
<div className="examInfo">
<h1>Manage Exam</h1>
</div>
<div className="left">
<div className="leftForm">
<div className="leftTitle">
Exam information
</div>
<br />
<div className="leftTitle">
</div>
<form onSubmit={handleUpdate}>
<label >Exam Title</label>
<input
type="text"
placeholder={title.doc}
value={title}
onChange={e => setTitle(e.target.value)}/>
<label htmlFor="">Description</label>
<textarea
id="desc"
cols="30"
rows="7"
value={description}
onChange={e =>setDesc(e.target.value)}
></textarea>
<button type="submit">Update</button>
</form>
</div>
</div>
<div className="right">
<div className="rightForm">
<div className="rightTitle">
Add Questions
<Link to= {`add_question`}style={{textDecoration:"none"}} className="link" >
Add new
</Link>
</div>
<div className="rightContainer">
{/* <p>1. What is the Meaning of db?</p> */}
{/* <div>
<input type="radio" name="option1" value="database" checked/>
<label htmlFor="">database</label>
</div>
<div>
<input type="radio" name="option2" value="data" disabled/>
<label htmlFor="">data</label>
</div>
<div>
<input type="radio" name="option3" value="databytes" disabled/>
<label htmlFor="">databytes</label>
</div>
<div>
<input type="radio" name="option4" value="databoard" disabled/>
<label htmlFor="">databoard</label>
</div>
<br />
<button>update</button>
<button>delete</button> */}
</div>
</div>
</div>
</div>
</div>
)
}
export default ManageExam
export const Examtable = ({id}) => {
const [list,setExamlist] = useState([])
// function to call the list from the firestore
useEffect (()=>{
const unsub = onSnapshot(
collection(db, "Exams"), //"exams -> pangalan ng database/("collection") ko"
(snapShot) => {
let list = [];
snapShot.docs.forEach((doc) => {
list.push({ id: doc.id, ...doc.data() });
});
setExamlist(list);
console.log(list.id);
},
(error) => {
console.log(error);
}
);
return () => {
unsub();
};
},[]);
const handleDelete = async (id) => {
alert("Do you want to delete?")
//window.confirm("Are you sure you want to delete?");
try {
await deleteDoc(doc(db, "Exams", id));
setExamlist(list.filter((item) => item.id !== id));
console.log(id)
} catch (err) {
console.log(err);
}
};
const actionColumn = [{field: "action", headerName: "Action", width: 200, renderCell:(params)=>{
return(
<div className="cellAction">
<div className="manageButton"> {/*/exam/manage_exam*/}
<Link to={`/exam/manage_exam/${params.row.id}`} style={{textDecoration:"none"}} className="link" >
Manage
</Link>
</div>
<div className="deleteButton" onClick={() => handleDelete(params.row.id)}>Delete</div>
</div>
)
}}];
return (
<div className="examtable" >
<div className="examtableTitle">
Exam
<Link to="/exam/new_exam/" style={{textDecoration:"none"}} className="link">
Add new
</Link>
</div>
<DataGrid
className="datagrid"
rows={list} //eto mga list nung nasa firebase
columns={examColumns.concat(actionColumn)}
pageSize={9}
rowsPerPageOptions={[9]}
checkboxSelection
/>
</div>
)
}
export default Examtable
here is the examtable.jsx where all the document in the collection will be displayed.
when i click the manage button, the url will display like this (localhost:3000/exam/manageexam/3BelYq7lMxRNrWKknCRK,, its because i click on this document but i cant update it at all because the console always said the id was undefined. i hope you understand what im saying
Because your pass id with Link in Examtable file.I think u must use useParams from react-router-dom in ur ManageExam.
First you need add id in your route path file, like this.
path: '/exam/manageexam/:id'
And then, in ur ManageExam.
import {useParams} from 'react-router-dom'
const ManageExam = () => {
const {id} = useParams()
const [description,setDesc]=useState("")
const [title,setTitle]=useState("")
function handleUpdate(e){
e.preventDefault();
const examcollref = doc(db,'Exams', id)
updateDoc(examcollref,{
title:title,
description:description
} ).then(response => {
alert("updated")
}).catch(error =>{
console.log(error.message)
})

Grabbing the Value of a Dynamically Created Object

I am dynamically creating buttons from an API call that looks like this:
My goal is that when a button is clicked the inner text will display in the search bar above.
below is the code for this auto complete component:
const Autocomplete = (props) =>
{
const btnSearch = (e) => {
console.log(props.suggestions)
}
return(
<>
{props.suggestions.map((e) => (
<button className={style.btn} onClick={btnSearch} key={e}>{e}</button>
))}
</>
);
}
export default Autocomplete;
The Autocomplete component is then being placed in a div as seen here:
return (
<>
<div className={style.container}>
<div className={style.title_hold}>
<h1>turn one</h1>
<h2>a search engine and game companion for Magic: The Gathering</h2>
</div>
<input className={style.search} type='text' placeholder='search for cards here...' value={search} onChange={handleInputChange} onKeyPress={handleSubmit}></input>
<div className={style.btn_wrap}>
<Autocomplete suggestions={results} />
</div>
<div className={style.data_wrap} id='user_display'>
<div className={style.img_wrap}>
{photos}
</div>
<div className={style.display_info}>
<h2>{card.name}</h2>
<h2>{card.type_line}</h2>
<h2>{card.oracle_text}</h2>
</div>
</div>
</div>
</>
)
Any help would be appreciated.
You can create a state variable in your parent component and then pass a function to the Autocomplete's button for the onClick which will then update the state in the parent. Something like this:
const Autocomplete = (props) => {
return(
<>
{props.suggestions.map((e) => (
<button className={style.btn} onClick={() => props.setSearch(e)} key={e}>{e}</button>
))}
</>
);
}
export default Autocomplete;
Your parent component:
import React from 'react'
const ParentComponent = (props) => {
const [searchText, setSearchText] = React.useState("")
const handleClick = (textFromButtonClick) => {
setSearchText(textFromButtonClick)
}
return (
<>
<div className={style.container}>
<div className={style.title_hold}>
<h1>turn one</h1>
<h2>a search engine and game companion for Magic: The Gathering</h2>
</div>
<input className={style.search} type='text' placeholder='search for cards here...' value={searchText} onChange={handleInputChange} onKeyPress={handleSubmit}></input>
<div className={style.btn_wrap}>
<Autocomplete setSearch={handleClick} suggestions={results} />
</div>
<div className={style.data_wrap} id='user_display'>
<div className={style.img_wrap}>
{photos}
</div>
<div className={style.display_info}>
<h2>{card.name}</h2>
<h2>{card.type_line}</h2>
<h2>{card.oracle_text}</h2>
</div>
</div>
</div>
</>
)
}
export default ParentComponent;
I took over your input value in the parent component, but without seeing any of your other code, I have no idea how you're managing that but you can likely merge it into this workflow to wire it up.

How can I search Giphy's GIF live with React.js?

Based on the official Giphy demo(CodeSandBox), I would like to create a live search function for Giphy GIFs.
And below is a demo of it.
search demo(CodeSandBox)
It holds the keyword as state and passes the keyword state to the search method of giphyFetch.
But the search results are not displayed.
Is there a problem with the code in the demo, or a solution to this problem?
Thank you.
source code
const giphyFetch = new GiphyFetch("sXpGFDGZs0Dv1mmNFvYaGUvYwKX0PWIh");
function App() {
const [keyword, setKeyword] = useState("");
const fetchGifs = (offset: number) =>
giphyFetch.search(keyword, { offset, limit: 10 });
return (
<>
<p>
<img src="./logo.gif" width="200" alt="Powered by GIPHY" />
</p>
<p>
input keyword
<input type="text" onChange={e => setKeyword(e.target.value)} />
</p>
<h4>search result</h4>
<Carousel fetchGifs={fetchGifs} gifHeight={200} gutter={6} />
</>
);
}
The Carousal does the fetchGifs once upon mount. So you need to force re-mount upon your input onChange. You can do this by adding dynamic key
Like this
...
<>
<p>
<img src="./logo.gif" width="200" alt="Powered by GIPHY" />
</p>
<p>
input keyword
<input
value={keyword}
type="text"
onChange={e => setKeyword(e.target.value)}
/>
</p>
<h4>search result</h4>
<Carousel
key={keyword}
fetchGifs={() => fetchGifs(5)}
gifHeight={200}
gutter={6}
/>
</>
...
Working demo is here

Resources