1

I need a little help trying to figure this out. I am using react native elements flatlist with a checkbox inside of it. I am also using react hooks with this. Everything is working perfectly but when I try and select one of the items in the checkbox it selects all of the items. Now I have had this issue before when I was just using components and not hooks and functions. I tried to use the same method that I used here Selecting multiple items

Like this...

function ViewCategoryWS2({navigation}) {
    const {category, setCategory} = useContext(ItemContext);
    const [eats, setEats] = useState([]);
    const [checked, toggleChecked] = useState(false); 
   
    function back() {
        navigation.navigate('MenuWS2');
    }
    
    function test(index) {
        const foods = category;
        foods[index].checked = !foods[index].checked;
        setCategory(foods);

    }
  
    return (
        
        <View style={styles.container}>
            
         
            <Icon 
                name='arrow-left'
                color="#000000"
                size={25}
                style={styles.menuIcon}
                onPress={back}
            />
          
            <FlatList
                data={category}
                //extraData={eats}
                keyExtractor={(item, index) => index.toString()}
                renderItem={({ item, index }) => (
                    <CheckBox 
                        center 
                        titleProps={{ color: 'black', fontWeight: 'bold'}}
                        title={item}
                        iconRight
                        checked={checked}
                        onPress={() => test(index)}
                        size={30}
                        containerStyle={styles.checkBox} 
                    />  
                    
                )}
            />
     
        
        </View>
       
    )
    

}

and I keep getting this error TypeError: Attempted to assign to readonly property. I have also tried it this way...

         <FlatList
                data={category}
                //extraData={eats}
                keyExtractor={(item, index) => index.toString()}
                renderItem={({ item, index }) => (
                    <CheckBox 
                        center 
                        titleProps={{ color: 'black', fontWeight: 'bold'}}
                        title={item}
                        iconRight
                        checked={checked}
                        onPress={() => toggleChecked(!checked)}
                        size={30}
                        containerStyle={styles.checkBox} 
                    />  
                    
                )}
            />

Here is my code from where the context is coming from. This page I pull data from my datbase and it displays categories. I click on any category and it pulls data from my database that's assigned to that certain category that was clicked on..

Here is the code...

import ItemContext from '../context/CategoryItems';

export default function menuWS({navigation}) {
    const [restaurantlocationcode, setRestaurantlocationcode] = useState('')
    const [menu, setMenu] = useState([]);
    const {category, setCategory} = useContext(ItemContext);
    const [selected, setSelected] = useState(0);

    function viewMenu() {
        fetch('URL', {
            method: 'POST',
            body: JSON.stringify({ restaurantlocationcode: restaurantlocationcode}),
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
        })
        .then(response => response.json())
        .then(response=> setMenu(response));
        console.log(menu);
        alert(menu);

    }
    
    function viewCategory({item}) {
        fetch('URL', {
            method: 'POST',
            body: JSON.stringify({
                category: item,
                restaurantlocationcode: restaurantlocationcode,
            }),
            headers: {
                'Accept': 'application/json',
                'Content-Type': 'application/json',
            },
        })
        .then(response => response.json())
        .then(response => {
            setCategory(response);
            console.log(response);
            alert(response);
        });
        navigation.navigate('ViewCategoryWS2', {category});
        
    }

    function showMenu() {
        console.log(menu);
        alert(menu);
    }

    
    const buttons = ['Menu']

    return (
        
        <View style={styles.container}>
            <Input
                style={styles.Input} 
                placeholder='Restaurant Location Code'
                leftIcon={
                    <Icon
                    name='location-arrow' 
                    size={24}
                    color='black'
                    />
                }
                onChangeText={setRestaurantlocationcode}
                value={restaurantlocationcode}
                underlineColorAndroid='transparent'
            />

            <ButtonGroup
                onPress={viewMenu}
                selectedIndex={selected}
                selectedButtonStyle={{backgroundColor: 'blue'}}
                buttons={buttons}
                containerStyle={styles.buttonGroup} 
            />


            <FlatList 
                data={menu}
                extraData={category}
                keyExtractor={(item, index) => index.toString()}
                renderItem={({item, index}) => (
                    <ListItem
                    titleStyle={{ color: 'black', fontWeight: 'bold'}}
                    title={item}
                    onPress={() => viewCategory({item})}
                    bottomDivider
                    chevron
                    />
                )}
            />
        
        </View>
        
    )

}

Here is my useContext code...

import { createContext } from 'react';

const ItemContext = createContext({});

export default ItemContext;

Here is the second part to my useContext code..

import React, {useState} from 'react';
import ItemContext from './CategoryItems';

const MenuItemState = ({children}) => {
    const [category, setCategory] = useState([]);
    return (
        <ItemContext.Provider value={{category, setCategory}}>

            {children}
        </ItemContext.Provider>
    )
}

export default MenuItemState;

And it just selects all of the items. I'm not sure what I am missing. Help with this would be greatly appreciated.

1 Answer 1

1

App Output:

enter image description here

import React, { useState } from 'react';
import { Text, View, StyleSheet, CheckBox, Icon, FlatList } from 'react-native';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';

/*
I am using this data, but you can continue
with the one you getting from context
*/
const data = [
  { id: 1, title: 'one', checked: true },
  { id: 2, title: 'two', checked: false },
  { id: 3, title: 'three', checked: false },
  { id: 4, title: 'four', checked: false },
  { id: 5, title: 'five', checked: false },
  { id: 6, title: 'six', checked: false },
];
export default function App() {
  const [category, setCategory] = useState(data);
  const [eats, setEats] = useState([]);
  const [checked, toggleChecked] = useState(false);

  function back() {
    // navigation.navigate('MenuWS2');
  }

  function test(index) {
    /* 
      Use this approach while changing the state. 
      This will create the copy of original array, 
      and you can perform mutation there 
      and update state with it.
    */
    console.log(index);
    const foods = [...category];
    foods[index].checked = !foods[index].checked;
    setCategory(foods);
  }

  /* 
    In your Checkbox component, 
    use "onChange" prop instead of "onPress" 
    and "value" instead of "checked" 
  */

  return (
    <View style={styles.container}>
      <FlatList
        data={category}
        //extraData={eats}
        keyExtractor={(item, index) => index.toString()}
        renderItem={({ item, index }) => (
          <Card style={{ padding: 10, margin: 5 }}>
            <Text>{item.title}</Text>
            <CheckBox
              center
              titleProps={{ color: 'black', fontWeight: 'bold' }}
              title={item}
              iconRight
              value={item?.checked}
              onChange={() => test(index)}
              size={30}
              containerStyle={styles.checkBox}
            />
          </Card>
        )}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    marginTop: 24,
    backgroundColor: 'grey',
    flex: 1,
  },
});

Working Example: Expo Snack

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you so much for taking time out to answer and help me with this. Ok so I followed exactly what you have here, and it got rid of the typeerror messages I was getting. But it's not selecting anything at all. I think it's the Value line in the checkbox component. Its giving me an error in my code when I put Value={item?.checked}.
Also when I click on any of the buttons nothing is console.logged. It seems like the onChange={} is not doing anything.
Logic and implementation from my side is perfect and you can see it works perfectly in the provided example expo link, for more details provide the context code from where you are getting the data. Problem is either with form of the data that I have used or something else.
oh yes don't get me wrong, your logic and implementation is working with the expo link you sent. That's why I am so puzzled because I copied exactly how you have it and mine is not clicking any item at all. I will add my context code to original question.
instead, post your code to the expo, it will be easy for me to look for problems faster.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.