1

I am trying to refactor my code into components. So right now I want to refactor the AddName component. This AddName component is to be pass to an event handler <form>(below the header Add Info). The problem right now is that now after refactoring the code, exporting and importing it and passing it to the event handler, I got an error in my VS code saying setPersons is assigned but never used. This is not something that I expect it to be since the other props in the AddName component have no problems but only this setPersons. I only know that to pass prop in between components, usually one will do it like this,

<AddName setPersons={setPersons}/>

In this situation it is not appropiate to use something like this right ? How can I fix this ? Below are my code,

App.js

import { useState } from 'react'
import AddName from './components/AddName'

const App = () => {
  const [persons, setPersons] = useState([
    { name: 'Arto Hellas', number: '012-3456789', id: 1 },
    { name: 'Ada Lovelace', number: '013-4567890', id: 2 },
    { name: 'Dan Abramov', number: '011-1234567', id: 3 },
    { name: 'Mary Poppendieck', number: '016-5556789', id: 4 }
  ])

  const [newName, setNewName] = useState('')
  const [newNumber, setNewNumber] = useState('')
  const [searchTerm, setSearchTerm] = useState("")

  const handleNameChange = (event) => {
    setNewName(event.target.value)
  }

  const handleNumberChange = (event) => {
    setNewNumber(event.target.value)
  }

  return (
    <div>
      <h2> Phonebook </h2>
      <input type="text" placeholder="Search..." onChange= {(event) => setSearchTerm(event.target.value)} />

      <h2> Add Info </h2>
      <form onSubmit={AddName}>
        <div>
          name: <input value={newName} onChange={handleNameChange} />
        </div>
        <div>
          phonenumber: <input value={newNumber} onChange={handleNumberChange} />
        </div>
        <div>
          <button type="submit"> add </button>
        </div>
      </form>

      <h2> Numbers </h2>

      <ul>
      {persons.filter((person) => {
        if (searchTerm === "") {
        return person
      } else if (person.name.toLowerCase().includes(searchTerm.toLowerCase())) {
        return person
      }
      }).map((person) => {
        return (
        <li key={person.name}> {person.name} {person.number} </li>
      );
      })
      }
      </ul>
    </div>
  )
}

export default App

AddName.js

const AddName = (props, event) => {
    event.preventDefault()

    const nameObject = {
      name: props.newName,
      number: props.newNumber2
    }

    const isNameExist = (value) => props.persons.some(person => person.name.includes(value))
    
    if (isNameExist(nameObject.name)) {
      alert("name already exist")
    } else {
      props.setPersons(props.persons.concat(nameObject))
      props.setNewName('')
      props.setNewNumber('')
    }
}

export default AddName
  • Here the AddName is not really a component, you made it like a function. I suggest you look into react hooks and creating custom ones and refactor AddName to be hook. – nadjagv Feb 18 '23 at 12:11
  • @nadjagv As I understand, react hook examples are like state hooks and effect hooks. In this case, do you mean I should move the const [persons, setPersons] = useState([...]) into the extracted component, AddName.js ? The problem with that is that the above hook variables are also used in another part in the code as in the 'ul' part. Hence if I move it, the main paragraph of information that has to be displayed in the browser loses it's data object – Jabri Juhinin Feb 18 '23 at 12:36
  • No, what I meant to say is to create your own hook. Hooks are at their core just functions. On the second thought, here is what I would do and what seems as the easiest fix to me at the moment: I would create function to handle onSubmit which calls AddName, for example handleAddName(event){ AddName(event, setPersons, setNewName, setNewNumber) }. You could access what user entered in form using event.target. Check it here: https://stackoverflow.com/questions/23427384/get-form-data-in-react – nadjagv Feb 18 '23 at 12:55
  • Additionally it seems to me that if you would do as I suggested, you do not actually need to save new number and new name in the state, but I do not know the rest of the logic so it is up to you. – nadjagv Feb 18 '23 at 12:57

1 Answers1

0

Why whould you pass a component to an onSubmit handler? Do you expect anything to render? I would have a simple function in the App component like this:

const addName = (event) => {
    event.preventDefault()

    const nameObject = {
      name: newName,
      number: newNumber2
    }

    const isNameExist = (value) => persons.some(person => person.name.includes(value))
    
    if (isNameExist(nameObject.name)) {
      alert("name already exist")
    } else {
      setPersons(persons.concat(nameObject))
      setNewName('')
      setNewNumber('')
    }
}
...
...
<form onSubmit={addName}>
...

I would also extract the list in another component otherwise also the list would rerender at all the state changes (i.e. at all input change)

e.pacciani
  • 206
  • 1
  • 6
  • I just want to make my code much cleaner and more simplified. Your suggestion above is actually my initial code and it works. But now I want to make the code in App.js to be more clean and more simplified. Hence the reason why I extract the addName component to new file AddName.js – Jabri Juhinin Feb 18 '23 at 12:32
  • The list you mean the array in const [persons, setPersons] = useState([.....]) ? – Jabri Juhinin Feb 18 '23 at 12:41