0

I am using ListItem from React Native Elements and have added a cheakbox:

{items.map((l, i) => (
    <ListItem.Swipeable
      key={i}
      <ListItem.CheckBox
        iconType='material'
        checkedIcon='clear'
        uncheckedIcon='add'
        checkedColor='red'
        checked={false}
        //onPress={something} Need to write (call here) function here that will change checked state and do other stuff
      />
      <ListItem.Content>
        <ListItem.Title>
          {l.time}
        </ListItem.Title>
      </ListItem.Content>
      <ListItem.Chevron />
    </ListItem.Swipeable>
  ))}

I need to be able to press on the ListItem.CheckBox and change the checked state as well as get the value of the mapped l object.

I know how to pass an l object from mapped array on the press to some function but don't know how to return value to checked={false}, and if it's possible do more stuff with this element.

I have read a lot about refs and almost all are about class-based components and about manually creating refs for specific elements. The issue here is that this is an array of elements mapped into listview so this needs to be done on the flay.

Keep in mind that examples from the documentation on the checkbox don't work in functional components. Example: checked={this.state.checked}

The point of this is to be able to select multiple items from the list and do some actions on objects that are tie to them.

Any pointers are appreciated.

react-native: 0.63.2

ikiK
  • 6,328
  • 4
  • 20
  • 40

1 Answers1

1

You can manage all state from the parent component while giving each child component a referance to setState (or a function that use setState inside). You can send checked of each object in the list to each corresponding child component as a prop. This way, as the state is kept in the parent component, each state change reflects on the UI. Sample component:

import { useState } from 'react'

const DEFAULT_ITEMS = [
  { id: "id_akdjk", label: "quora", checked: false },
  { id: "id_xlhwi", label: "library", checked: false },
  { id: "id_xoqix", label: "reddit", checked: true }
]


const ListItem = ({ label, checked, change }) => {
  return(
  <div>
    <input type="checkbox" onChange={change} checked={checked}/>
    <label htmlFor="vehicle1">{label}</label><br/>
  </div>
  )
}

export default function Component() {
  const [items, setItems] = useState(DEFAULT_ITEMS)

  const handleInputChange = (index) => {
    // manipulate copy of state. (not state itself)
    const copyState = [...items]

    // updating that specific indice
    copyState.splice(index,
                         1,
                         {...items[index], checked: !items[index]["checked"]})
    setItems(copyState)
  }

  return (
    <div>
      { items.map((el, i) => {
        return <ListItem 
                  key={i}
                  label={el.label}
                  checked={el.checked}
                  change={() => handleInputChange(i)}/>
      })}

      <div>
        <p>You chose:</p> { items.map((el) => el.checked ? el.label : '').join(' ') }
      </div>
    </div>
  )
}

So your onPress would be:

// assuming you are using this data as the state
const DEFAULT_ITEMS = [
  { id: "id_akdjk", checked: false },
  { id: "id_xlhwi", checked: false },
  { id: "id_xoqix", checked: false }
]

  ...
  const [items, setItems] = useState(DEFAULT_ITEMS)

  const handleInputChange = (index) => {
    // manipulate copy of state. (not state itself)
    const copyState = [...items]

    // updating that specific indice
    copyState.splice(index,
                         1,
                         {...items[index], checked: !items[index]["checked"]})
    setItems(copyState)
  }

  //...
  onPress={() => handleInputChange(i)}

P.S. using index to update state is not a good idea. Having an id for each object is a better practise

ABDULLOKH MUKHAMMADJONOV
  • 4,249
  • 3
  • 22
  • 40
  • Yeah, ill accept this. A neat trick that didn't cross my mind, I did it a bit differently but Logic is the same. Thanks for this. – ikiK Oct 10 '21 at 13:09
  • Also just to note I was hoping for a solution that does NOT need to modify my objects. I used them all over the place in-app. Putting the checked property just for the purpose of the list is a bit overkill. – ikiK Oct 11 '21 at 10:53
  • If you want I can update my answer to not use `checked` as a boolean. – ABDULLOKH MUKHAMMADJONOV Oct 11 '21 at 11:26
  • You don't have to write all code, you can say here if you have other ideas. That would also use states, right? Not ref's? – ikiK Oct 11 '21 at 14:08
  • I mean I could make a new array with only ids from items and attach checked state to them so I don't have to change the initial object, but I still don't like it. Im surprised there are no ref's solutions for this, and to target elements. – ikiK Oct 11 '21 at 14:15
  • 1
    As my instructor suggests refs solution is not a good option. In your case you would need to generate dynamic refs. You can do it [https://stackoverflow.com/questions/55995760/how-to-add-refs-dynamically-with-react-hooks], but I really do not like the idea at all – ABDULLOKH MUKHAMMADJONOV Oct 11 '21 at 14:25
  • Thanks, ill keep it as it is probably. Just wanted to know all options – ikiK Oct 11 '21 at 14:51