Search code examples
reactjsreact-nativeconditional-rendering

how can conditional rendering reflect the state from a list of Boolean using hook?


The Goal:

My React Native App shows a list of <Button /> based on the value from a list of Object someData. Once a user press a <Button />, the App should shows the the text that is associated with this <Button />. I am trying to achieve this using conditional rendering.

The Action:

So first, I use useEffect to load a list of Boolean to showItems. showItems and someData will have the same index so I can easily indicate whether a particular text associated with <Button /> should be displayed on the App using the index.

The Error:

The conditional rendering does not reflect the latest state of showItems.

The Code:

Here is my code example

import {someData} from '../data/data.js';

const App = () => {
  const [showItems, setShowItems] = useState([]);

  useEffect(() => {
    const arr = [];
    someData.map(obj => {
      arr.push(false);
    });
    setShowItems(arr);
  }, []);

  const handlePressed = index => {
    showItems[index] = true;
    setShowItems(showItems);
    //The list is changed. 
    //but the conditional rendering does not show the latest state
    console.log(showItems);
  };

  return (
    <View>
      {someData.map((obj, index) => {
        return (
          <>
            <Button
              title={obj.title}
              onPress={() => {
                handlePressed(index);
              }}
            />
            {showItems[index] && <Text>{obj.item}</Text>}
          </>
        );
      })}
    </View>
  );
};



Solution

  • showItems[index] = true;
    setShowItems(showItems);
    

    React is designed with the assumption that state is immutable. When you call setShowItems, react does a === between the old state and the new, and sees that they are the same array. Therefore, it concludes that nothing has changed, and it does not rerender.

    Instead of mutating the existing array, you need to make a new array:

    const handlePressed = index => {
      setShowItems(prev => {
        const newState = [...prev];
        newState[index] = true;
        return newState;
      });
    }