Sylvio
Sylvio

Reputation: 25

"TypeError: visible.map is not a function" when toggling button

Trying to render a list in React. I want each button to toggle visibility of a component with some content (this is going to be a reel of projects). I get the list rendered just as I expect it to, but whenever I click one of the buttons, I get "TypeError: visible.map is not a function". The code worked when I rendered each component individually, but when I introduced the state and .map, suddenly we stopped being friends...

Parent:

import { useState } from 'react';

import ExampleOne from './Examples/exampleOne.js';
import ExampleTwo from './Examples/exampleTwo.js';
import ExampleThree from './Examples/exampleThree.js';

function SectionTwo() {

     const [visible, setVisible] = useState([
        { number: 1, content: < ExampleOne setVisible = { visible => setVisible(visible => !visible)} />, visible: false },
        { number: 2, content: < ExampleTwo setVisible = { visible => setVisible(visible => !visible)} />, visible: false },
        { number: 3, content: < ExampleThree setVisible = { visible => setVisible(visible => !visible)} />, visible: false }
    ]);
 
    return ( 

        <div className="section-content seciton2">
            <p>We're no strangers to love<br/>
            You know the rules and so do I<br/>
            A full commitment's what I'm thinking of<br/>
            You wouldn't get this from any other guy<br/>
            I just wanna tell you how I'm feeling<br/>
            Gotta make you understand</p>

            
                    {visible.map((i) => (
                <ul className="examples"
                    onClick={() => setVisible(visible => !visible)}
                    key={i.number}
                >
                    <button className={ 'example' + i.number } onClick={() => setVisible(visible => !visible)}></button>
                </ul>
                ))}
                

        </div>

    );
  }

export default SectionTwo;

Children:

import { useEffect, useRef } from 'react';

function ExampleThree(props) {

    let exampleRef = useRef();

    useEffect (() => {
        let handler = (event) => {
            if (!exampleRef.current.contains(event.target)) {
            props.setVisible(false);
            }
        }
        
        document.addEventListener("mousedown", handler);

        return () => {
            document.removeEventListener("mousedown", handler)
        }
    });



    return ( 
  
        <div className="example3-content" ref={exampleRef}>

            <p>We're no strangers to love<br/>
            You know the rules and so do I<br/>
            A full commitment's what I'm thinking of<br/>
            You wouldn't get this from any other guy<br/>
            I just wanna tell you how I'm feeling<br/>
            Gotta make you understand</p>
            
            <button onClick={() => props.setVisible(visible => !visible)}>ha det</button>

        </div>

    );
  }

export default ExampleThree;

(Never mind the placeholder text, I'm just tired of Lorem Ipsum...)

Upvotes: 0

Views: 450

Answers (2)

Aykut Burak SAFAK
Aykut Burak SAFAK

Reputation: 332

There're so many problems in this code and I didn't really understand what you're trying to accomplish, so I'm not going to try to improve it. But I'll do a quick code-review and give you some suggestions;

  • I'd suggest you should never change the type of a state element (in this example, visible changes from array to boolean, which causes the error)
  • You should also avoid declarative programming, means you should avoid useRef if you're not sure what you're doing
  • I'd co-locate the state where it belongs (visibility state of a component belongs to the component itself not the parent component)
  • You should use JSX over JSON where applicable, that means I'd never use an array to map over instead I'd use the power of JSX and wrote those "content"s directly

Upvotes: 0

Eusbolh
Eusbolh

Reputation: 126

setVisible(visible => !visible)

This code piece probably doesn't do what you think. Initially you have an array of objects set to the state named visible. When you negate it, it just becomes false. Therefore, it cannot invoke the map function on a state with a value false.

Upvotes: 2

Related Questions