I have a problem where I am trying to click on a certain div being returned by my backend and update it. I am trying to have it setup so that you click edit and the blogTitle and blogBody become input bars where you type in the new title and new body. In my code you can see an update that works and one that does not. The problem with the one that does not is that when I hit edit all blogBody’s and blogTitle’s become input bars instead of just one.
This 5 second of the issue video might make more sense than my explanation.
Now in my code this mainly deals with the following:
<div style={{display : 'flex', flexDirection: 'column-reverse'}}> { getBasic.miscData.map(({blogBody, blogTitle, _id}, i) => { return( <div key={i} > <p>{i}</p> {prompt ? <p>{blogBody}</p> : <input onChange={handleChange} name='newerValue' value={Item.newerValue} placeholder='new title'></input>} {prompt ? <p>{blogTitle}</p> : <input onChange={handleChange} name='newerValue2' value={Item.newerValue2} placeholder='new title'></input>} <p>{blogTitle}</p> <p>{_id}</p> <button onClick={deleteOne} value={_id}>Delete</button> {prompt ? <button onClick={() => { setPrompt(!prompt)}} >Edit</button> : <button onClick={() => { setPrompt(!prompt)}} >Submit</button>} </div>
Here is the full code:
import './App.css'; import axios from 'axios'; import React, { useState, useEffect } from 'react' function App() { const [getBasic, setGetBasic] = useState() const [Item, setItem] = useState( { title: '', description: '', id: '', newValue: '', newValue2: '', newerValue: '', newerValue2: '', previousValue: '' } ) const [prompt, setPrompt] = useState(true) async function fetchData() { await axios.get('http://localhost:3001/api') .then(result => setGetBasic(result.data)) } function handleChange(event) { let {name, value} = event.target; setItem(prevInput => { return( { ...prevInput, [name]: value, } ); }); // console.log(Item); } //delete function deleteOne(event) { event.preventDefault(); const aValue = event.target.value; const deleteItem = { // id: Item.id id: aValue } console.log(deleteItem) axios.post('http://localhost:3001/api/delete', deleteItem); window.location.reload(); // console.log(deleteItem) } function updateOne(event) { event.preventDefault(); const updatedItem = { previousValue: Item.previousValue, newValue: Item.newValue, newValue2: Item.newValue2 } console.log(updatedItem) axios.put('http://localhost:3001/api/update', updatedItem); window.location.reload(); // console.log(deleteItem) } useEffect(() => { fetchData() }, []) if (getBasic) { return ( <div className="App"> <br /> {/* A version of update that works */} <input onChange={handleChange} name="previousValue" value={Item.previousValue} placeholder="old value id" /> <input onChange={handleChange} name='newValue' value={Item.newValue} placeholder='new title'></input> <input onChange={handleChange} name='newValue2' value={Item.newValue2} placeholder='new body'></input> <button onClick={updateOne} >update</button> {/* A version of update that does not work*/} <div style={{display : 'flex', flexDirection: 'column-reverse'}}> { getBasic.miscData.map(({blogBody, blogTitle, _id}, i) => { return( <div key={i} > <p>{i}</p> {prompt ? <p>{blogBody}</p> : <input onChange={handleChange} name='newerValue' value={Item.newerValue} placeholder='new title'></input>} {prompt ? <p>{blogTitle}</p> : <input onChange={handleChange} name='newerValue2' value={Item.newerValue2} placeholder='new title'></input>} <p>{blogTitle}</p> <p>{_id}</p> <button onClick={deleteOne} value={_id}>Delete</button> {prompt ? <button onClick={() => { setPrompt(!prompt)}} >Edit</button> : <button onClick={() => { setPrompt(!prompt)}} >Submit</button>} </div> )})} </div> </div> )} else { return ( <div> <h1>Loading</h1> </div> ) }; } export default App;
Now I understand why it is doing this, I just cannot think through the logic of getting my edit button to only edit one at a time. Also I understand the update will not work once I fix this, I am trying to solve this problem of editing 1 at a time first before setting it up how the other update one is.
Edit: so far I received one dislike and no comments I re read through this and realized it lacks a bit of focus thus made the code simpler:
import './App.css'; import axios from 'axios'; import React, { useState, useEffect } from 'react' function App() { const [getBasic, setGetBasic] = useState() const [Item, setItem] = useState( { title: '', description: '', id: '', newerValue: '', newerValue2: '', previousValue: '' } ) const [prompt, setPrompt] = useState(true) async function fetchData() { await axios.get('http://localhost:3001/api') .then(result => setGetBasic(result.data)) console.log(getBasic) } useEffect(() => { fetchData() }, []) if (getBasic) { return ( <div className="App"> <div style={{display : 'flex', flexDirection: 'column-reverse'}}> { getBasic.miscData.map(({blogBody, blogTitle, _id}, i) => { return( <div key={i} > <p>{i}</p> {prompt ? <p>{blogBody}</p> : <input ></input>} {prompt ? <p>{blogTitle}</p> : <input ></input>} <p>{blogTitle}</p> <p>{_id}</p> {prompt ? <button onClick={() => { setPrompt(!prompt)}} >Edit</button> : <button onClick={() => { setPrompt(!prompt)}} >Submit</button>} </div> )})} </div> </div> )} else { return ( <div> <h1>Loading</h1> </div> ) }; } export default App;
This is all thats needed to work with to solve the issue at hand which is edit one at a time instead of all of them. Leaving the op for reference.
Advertisement
Answer
Have a component for each element so they each have their own unique prompt
For example,
//Element.js
import React from "react"; export default function Element({ i, blogTitle, handleChange, _id, deleteOne, blogBody, Item }) { const [prompt, setPrompt] = React.useState(true); return ( <div> <p>{i}</p> {prompt ? ( <p>{blogBody}</p> ) : ( <input onChange={handleChange} name="newerValue" value={Item.newerValue} placeholder="new title" ></input> )} {prompt ? ( <p>{blogTitle}</p> ) : ( <input onChange={handleChange} name="newerValue2" value={Item.newerValue2} placeholder="new title" ></input> )} <p>{blogTitle}</p> <p>{_id}</p> <button onClick={deleteOne} value={_id}> Delete </button> {prompt ? ( <button onClick={() => { setPrompt(!prompt); }} > Edit </button> ) : ( <button onClick={() => { setPrompt(!prompt); }} > Submit </button> )} </div> ); }
//App.js
Now in the body return of your main file you could just do this
First import import Element from "./Element";
Then add the new component with specified props
{getBasic.miscData.map(({ blogBody, blogTitle, _id }, i) => { return ( <Element i={i} blogTitle={blogTitle} handleChange={handleChange} _id={_id} deleteOne={deleteOne} blogBody={blogBody} Item={Item} /> ); })}