0

I have data that looks like this:

// items.json    
[
      {
        "key": 1,
        "category": "Fruits",
        "colors": [
          {
            "color": "red",
            "favourite": "apple"
          },
          {
            "color": "orange",
            "favourite": "orange"
          }
        ]
      }, 
      {
        "key": 2,
        "category": "Vegetables",
        "colors": [
          {
            "color": "orange",
            "favourite": "carrot"
          },
          {
            "color": "green",
            "favourite": "celery"
          }
        ]
      }
    ]

But it can have an unlimited amount of objects in each array. What I want to do is initially display the categories, which I have done like this:

import Items from './items.json';

// and then I use it in the render method

    render() {
        var items= items;
    return (
         {items.map(item =>
             <TouchableOpacity
                 key={item.key}>
                <Text>
                  {item.category}
                </Text>
             </TouchableOpacity>
          )}
    )
}

Now when a category is pressed I want to hide the categories and display the colors. And then when the color is pressed I want to hide the colors and display the favourite.

I have tried doing this with if else statements, but it that won't work if the data is replaced, and as I mentioned this json object can be quite large. Please help!

2 Answers 2

1

Declare two arrays in your state, one for storing the original data and one for storing the filtered data based on which item was pressed.

state = {
  items: items, // original data
  data: items, // will filter data and display using .map()
  categoryIndex: 0, // index of the selected category
};

Add onPress to your TouchableOpacity and pass the type of the item that was pressed.

{this.state.data.map((item, index) => (
  <TouchableOpacity
    onPress={() =>
      this.onItemPress(
        item.category ? 'category' : item.color ? 'color' : 'favourite',
        index
      )
    }
    key={item.key}>
    <Text>{item.category || item.color || item.favourite}</Text>
  </TouchableOpacity>
))}

onItemPress, based on item that was pressed update state.data

onItemPress = (type, index) => {
  if (type === 'category') {
    this.setState({
      data: this.state.items[index].colors,
      categoryIndex: index,
    });
  }

  if (type === 'color') {
    this.setState({
      data: [
        {
          favourite: this.state.items[this.state.categoryIndex].colors[index]
            .favourite,
        },
      ],
    });
  }

  if (type === 'favourite') {
    this.setState({
      data: this.state.items,
      categoryIndex: 0,
    });
  }
};

DEMO

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

1 Comment

Thank you so much! This is such a nice clean solution. I was wondering if it was possible to expand on this to have different renderings for each type?
1

You need to:

  • track in your component state what the selected item or color index is so your render function knows when to rerender and what to render.
  • handle when an item is pressed by adding the onPress prop to your TouchableOpacity and updating the component state as mentioned above
    state = {
        selectedItemIndex: null,
        selectedColorIndex: null,
    };

    render {
        if (this.state.selectedColorIndex) {
           // return some jsx using this data below:
           // items[this.state.selectedItemIndex].colors[this.state.selectedColorIndex].favourite
        }        

        if (this.state.selectedItemIndex) {
            return (
                {items[this.state.selectedItemIndex].colors.map(color, i) => (
                    {/* return jsx here for colors */}
                )}
            );
        }

        return (
            {items.map((item, i) => (
                 <TouchableOpacity
                     key={item.key} 
                     onPress={() => this.setState({ selectedItemIndex: i })}>
                     <Text>
                         {item.category}
                     </Text>
                 </TouchableOpacity>
          ))}
        )
    }

Comments

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.