Search code examples
javascriptreactjsarraysdictionaryfind

How to return objects in ReactJS that can be edited and removed from an array?


// imports
import { useState } from 'react';
import { useAuthContext } from '../../hooks/useAuthContext';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {  faPlus, faTrashCan } from '@fortawesome/free-solid-svg-icons';

// styles
import './Create.css';

export default function Create() {
  const { user } = useAuthContext();
  
  const [projectTitle, setProjectTitle] = useState('');
  const [projectDescription, setProjectDescription] = useState('');
  const [projectThumnbnail, setProjectThumbnail] = useState('');
  const [projectKeywords, setProjectKeywords] = useState([]);
  const [stepsMade, setStepsMade] = useState(1);
  const [steps, setSteps] = useState([{ photoSrc: '', stepDescription: 'hi nice to meet you', stepThumbnail: null, id: 0 },]);

  const handleNewStep = () => {
    console.log(stepsMade);
    setStepsMade(prevStepsMade => prevStepsMade + 1);
    console.log(steps)
    setSteps(prevSteps => [...prevSteps, { photoSrc: '', stepDescription: 'hi nice to meet you', stepThumbnail: null, id: stepsMade }])
  }

  const handleRemoveStep = id => {
      setSteps(prevSteps => prevSteps.filter(step => step.id !== id)); 
      console.log(steps)
  }

  const handleUpdateStepThumbnail = (value, id) => {
    setSteps(prevSteps => prevSteps.map(s => { 
      if(s.id === id) {
        return {...s, stepThumbnail: value};
      } else {
        return s;
      }
  }))
  }

  const handleUpdateStepDescription = (value, id) => {
    setSteps(prevSteps => prevSteps.map(s => { 
      if(s.id === id) {
        return {...s, stepDescription: value};
      } else {
        return s;
      }
  }))  
  }

  return (
    <div>
      <label>
        <span>project name:</span>
        <input type='text' />
      </label>

      <label>
        <span>project description:</span>
        <input type='text' />
      </label>

      <label>
        <span>project keywords:</span>
        <input type='text' />
      </label>

      <label>
        <span>project picture:</span>
        <input type='file' />
      </label>

      {steps.map((step, index) => (   
      <div className='project-step' key={index}>
        <div>
          <FontAwesomeIcon icon={faTrashCan} onClick={() => { {handleRemoveStep(step.id)} }}/>
        </div>
        <img src={step.photoSrc}/>
        <input type='file' defaultValue={step.stepThumbnail} onChange={e => handleUpdateStepThumbnail(e.target.value, step.id)}/>
        <input type='text' defaultValue={step.stepDescription} onChange={e => handleUpdateStepDescription(e.target.value, step.id)}/>
      </div>
      ))}

      <div>
        <FontAwesomeIcon icon={faPlus} onClick={handleNewStep}/>
      </div>
    </div>
  )
}

So everytime I try to remove one step, the last one gets removed instead of the one I wanted. Maybe there is a problem with setSteps function in handleUpdateStepDescription / Thumbnail or it has to be made in a completely different way? Also all of the steps need to stay at the same place in the array.


Solution

  • So basically index should not be used as key of the element. Much better option is step.id

    {steps.map(step => (   
          <div className='project-step' key={step.id}>
            <div>
              <FontAwesomeIcon icon={faTrashCan} onClick={() => { {handleRemoveStep(step.id)} }}/>
            </div>
            <img src={step.photoSrc}/>
            <input type='file' defaultValue={step.stepThumbnail} onChange={e => handleUpdateStepThumbnail(e.target.value, step.id)}/>
            <input type='text' defaultValue={step.stepDescription} onChange={e => handleUpdateStepDescription(e.target.value, step.id)}/>
          </div>
          ))}