skip to Main Content

In my app, SearchParams.tsx is a form that gets the apiResponse from the parent and uses entries in this response to set options for it’s select/dropdown menus for the user to then choose from. I have a lot of states in this component, few for setting the options available and others for tracking the options the user has selected (to submit/post on form submit). I am wondering if there is a more elegant/cleaner/concise way to do this (except combining everything in one object)? Or if having separate states tracking everything individually is a good idea in react? Is one approach better than the other? etc.

Note: I am using a third party API so don’t have any control on that front.

Here is a snippet from SearchParams.tsx:

const SearchParams = ({ apiResponse, speciesSelected }: { apiResponse: SpeciesSelectionResponse| {}, speciesSelected: string }) => {

    const [desiredAge, setDesiredAge] = useState<string>("")
    const [desiredGender, setDesiredGender] = useState<string>("")
    const [desiredGeoRange, setDesiredGeoRange] = useState<string>("35")
    const [desiredColor, setDesiredColor] = useState<string>("")
    const [desiredBreed, setDesiredBreed] = useState<string>("")
    const [zipCode, setZipCode] = useState<string>("")
    const [species, setSpecies] = useState<string>("")
    
    const [ageOptionsAvailable, setAgeOptionsAvailable] = useState<SubObject[]>([])
    const [genderOptionsAvailable, setGenderOptionsAvailable] = useState<SubObject[]>([])
    const [geoRangeOptionsAvailable, setGeoRangeOptionsAvailable] = useState<SubObject[]>([])
    const [colorOptionsAvailable, setColorOptionsAvailable] = useState<SubObject[]>([])
    const [breedOptionsAvailable, setBreedOptionsAvailable] = useState<SubObject[]>([])

    useEffect(() => {
        if (Object.keys(apiResponse).length === 0 && apiResponse.constructor === Object) {
            return
        }
        if (Object.keys(apiResponse).length !== 0 && apiResponse.constructor === Object) {
            setAgeOptionsAvailable((apiResponse as SpeciesSelectionResponse).age)
            setGenderOptionsAvailable((apiResponse as SpeciesSelectionResponse).sex)
            setGeoRangeOptionsAvailable((apiResponse as SpeciesSelectionResponse).geo_range)
            setColorOptionsAvailable((apiResponse as SpeciesSelectionResponse).color_id)
            setBreedOptionsAvailable((apiResponse as SpeciesSelectionResponse).breed_id)
            setSpecies(speciesSelected)
        }
    }, [apiResponse])

Everything works as expected. I am just wondering if there is a more elegant/concise way of refactoring this.

2

Answers


  1. I would say that you don’t need to wrap inputs in state.

    Presumably the other state is displayed, and set by controls on this form. In that case it good to have states for each individually.

    const SearchParams = ({ apiResponse, speciesSelected }: { apiResponse: SpeciesSelectionResponse| {}, speciesSelected: string }) => {
    
        const hasResponse = Object.keys(apiResponse).length !== 0 && apiResponse.constructor === Object
    
        const [desiredAge, setDesiredAge] = useState<string>("")
        const [desiredGender, setDesiredGender] = useState<string>("")
        const [desiredGeoRange, setDesiredGeoRange] = useState<string>("35")
        const [desiredColor, setDesiredColor] = useState<string>("")
        const [desiredBreed, setDesiredBreed] = useState<string>("")
        const [zipCode, setZipCode] = useState<string>("")
        const species = hasResponse ? speciesSelected : ""
        
        const ageOptionsAvailable = hasResponse ? apiResponse.age : []
        const genderOptionsAvailable = hasResponse ? apiResponse.sex : []
        const geoRangeOptionsAvailable = hasResponse ? apiResponse.geo_range : []
        const colorOptionsAvailable = hasResponse ? apiResponse.color_id : []
        const breedOptionsAvailable = hasResponse ? apiResponse.breed_id : []
    
        // etc
    }
        
    
    Login or Signup to reply.
  2. Although there is no specific pattern, I suggest that You don’t need to create a state for every entity. You can create an object state for related entities.

    const [species,setSpecies] = useState<object>({})
    
    //You can set state like
    setSpecies({
    desiredAge:245,
    desiredGender:'female',
    desiredGeoRange:'YourRange',
    desiredColor:'yourColor',
    desiredBreed:'YourBreed',
    })
    

    And to use any state for dependency you can use

    useeEffect(()=>,[species. desiredBreed])
    

    To set the specific entity you can do like

    setSpecies((prev)=>({...prev,desiredColor:'yourColor'}))
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search