0
votes

I have an issue mapping over a passing prop, from the parent component (App.js) to the child component (Label.js). the terminal showing me a success compiling with warning. when i just click the login button in my application, i directly got an alert says: "Cannot read property 'map' of undefined" and after clicking ok, this error is showing: "TypeError: Cannot read property 'map' of undefined is showing when I'm trying to map over the props passed from parent component to child component". I'm new to React hooks, Any help is much appreciated, and excuse the long lines of code. Thank you

App.js

import Label from "./Label";
import Register from "./Registration";

export default function App() {
  const [add_task_data, setAddTaskData] = useState({
    title: "",
    description: "",
    date: "",
    priority: "",
  });

  const [state, setState] = useState({
    isAuthenticated: false,
  });
  const [login, setLogin] = useState({
    email: "",
    password: "",
  });


  const [todos, setTodos] = useState([]);

  const fetchTodos = () => {
    if (state.isAuthenticated) {
      var myHeaders = new Headers();
      myHeaders.append("Accept", "application/json");
      myHeaders.append(
        "Authorization",
        `Bearer ${localStorage.getItem("access_token")}`
      );

      var requestOptions = {
        method: "GET",
        headers: myHeaders,
        redirect: "follow",
      };

      fetch("https://codeminos-todo.tk/api/v1/to-dos", requestOptions)
        .then((response) => response.text())
        .then((json) => {
          const result = JSON.parse(json);
          setTodos(result.data);
        })
        .catch((error) => console.log("error", error));
    }
  };
  
  // const checkUserAuth = () => {
    if (state.isAuthenticated) {
      var myHeaders = new Headers();
      myHeaders.append("Accept", "application/json");
      myHeaders.append(
        "Authorization",
        `Bearer ${localStorage.getItem("access_token")}`
      );

      var requestOptions = {
        method: "GET",
        headers: myHeaders,
        redirect: "follow",
      };

      fetch("https://codeminos-todo.tk/api/v1/labels", requestOptions)
        .then((response) => response.text())
        .then((json) => {
          setState({
            isAuthenticated: true,
          });
        })
        .catch((error) => {
          setState({
            isAuthenticated: false,
          });
        });
    }
  // };

  // const fetchLabels = () => {
  //   if (state.isAuthenticated) {
  //     var myHeaders = new Headers();
  //     myHeaders.append("Accept", "application/json");
  //     myHeaders.append(
  //       "Authorization",
  //       `Bearer ${localStorage.getItem("access_token")}`
  //     );

  //     var requestOptions = {
  //       method: "GET",
  //       headers: myHeaders,
  //       redirect: "follow",
  //     };


  //   }
  // };
  
  // useEffect(() => {
  //   fetchTodos();
  //   // fetchLabels();
  // }, [state.isAuthenticated]);
  
  function handleChange(key, value) {
    setAddTaskData({
      ...add_task_data,
      [key]: value,
    });
  }
  function hanldeLoginChange(key, value) {
    setLogin({
      ...login,
      [key]: value,
    });
  }
  const handleLoginSubmit = (event) => {
    event.preventDefault();
    var myHeaders = new Headers();
    myHeaders.append("Accept", "application/json");
    myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

    var urlencoded = new URLSearchParams();
    urlencoded.append("email", "[email protected]");
    urlencoded.append("password", "212312322");

    var requestOptions = {
      method: "POST",
      headers: myHeaders,
      body: urlencoded,
    };

    fetch("https://codeminos-todo.tk/api/login",requestOptions) 
     
      .then((response) => {
        return response.json();
      })
      .then((data) => {
        if (data.access_token !== undefined) {
          localStorage.setItem("access_token", data.access_token);
          setState({
            ...state,
            isAuthenticated: true,
          });
        }
      })
      .catch((error) => {
        alert(error.message);
      });
  };

  const handleAddToDoSubmit = (event) => {
    event.preventDefault();
    var myHeaders = new Headers();
    myHeaders.append("Accept", "application/json");
    myHeaders.append(
      "Authorization",
      `Bearer ${localStorage.getItem("access_token")}`
    );
    myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

    var urlencoded = new URLSearchParams();
    urlencoded.append("title", add_task_data.title);
    urlencoded.append("description", add_task_data.description);
    urlencoded.append("priority", add_task_data.priority);
    urlencoded.append("date", add_task_data.date);

    var requestOptions = {
      method: "POST",
      headers: myHeaders,
      body: urlencoded,
      redirect: "follow",
    };

    fetch("https://codeminos-todo.tk/api/v1/to-dos", requestOptions)
      .then((response) => response.text())
      .then((result) => {
        fetchTodos();
      })
      .catch((error) => console.log("error", error));
  };
  
  
  return (
    <>
      <div>
        <Register /> <br/>
        
        <br/>
      </div>
      <div className="App">
        <h2>Welcome to your task manager app</h2>

        {!state.isAuthenticated && (
          <div>
            <h2>You are not authenticated, please login</h2>

            <form onSubmit={(event) => handleLoginSubmit(event)}>
              <div>
                <label>Email: </label>
                <input
                  type="text"
                  name="email"
                  onChange={(event) => {
                    hanldeLoginChange("email", event.target.value);
                  }}
                />
              </div>
              <div>
                <label>password</label>

                <input
                  type="text"
                  name="password"
                  onChange={(event) => {
                    hanldeLoginChange("password", event.target.value);
                  }}
                />
              </div>
              <input type="submit" value="login" />
            </form>
          </div>
        )}
        {state.isAuthenticated && (
          <div>
            <h2>Tasks</h2>
            {todos.map((todo) => {
              return (
                <div>
                  Title {todo.title} --- description: {todo.description}
                </div>
              );
            })}

            
            <button
              onClick={() => {
                setState({
                  ...state,
                  isAuthenticated: false,
                });
                localStorage.removeItem("access_token");
              }}
            >
              Logout
            </button>
            <h2>Add TODO</h2>
            <form
              onSubmit={(event) => {
                handleAddToDoSubmit(event);
              }}
            >
              <div>
                <label>Title</label>
                <input
                  type="text"
                  name="title"
                  onChange={(event) => {
                    handleChange("title", event.target.value);
                  }}
                />
              </div>
              <div>
                <label>description</label>

                <input
                  type="text"
                  name="description"
                  onChange={(event) => {
                    handleChange("description", event.target.value);
                  }}
                />
              </div>
              <div>
                <label>date</label>

                <input
                  type="text"
                  name="date"
                  onChange={(event) => {
                    handleChange("date", event.target.value);
                  }}
                />
              </div>
              <div>
                <label>priority</label>
                <input
                  type="text"
                  name="priority"
                  onChange={(event) => {
                    handleChange("priority", event.target.value);
                  }}
                />
              </div>
              
              <Label {...add_task_data.title}/>
              
              <input type="submit" value="add todo" />
            </form>
            {JSON.stringify(add_task_data)}
          </div>
        )}
      </div>
    </>
  );
}

Label.js


export default function Label(props){
  const [labels, setLabels] = useState({ label: "" });
   const [state, setState] = useState({
     isAuthenticated: false,
   });

  function handleChangeLabel(key, value) {
    setLabels({
      ...labels,
      [key]: value,
    });
  }

     if (state.isAuthenticated) {
      const handleSubmitLabel = (event) => {
        event.preventDefault();

        var myHeaders = new Headers();
        myHeaders.append(
          "Authorization",
          `Bearer ${localStorage.getItem("access_token")}`
        );
        myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

        var urlencoded = new URLSearchParams();
        urlencoded.append("name", labels.label);

        var requestOptions = {
          method: "POST",
          headers: myHeaders,
          body: urlencoded,
          redirect: "follow",
        };

        fetch("https://codeminos-todo.tk/api/v1/labels", requestOptions)
          .then((response) => response.text())
          .then((json) => {
            const result = JSON.parse(json);
            setLabels(result.data);
             setState({
               isAuthenticated: true,
             });
          })
          .catch((error) => {
            setState({
               isAuthenticated: false,
             });
          });
      };
     }
  

  return (
    <>
      <form onSubmit={(event) => {handleSubmitLabel(event)}}>
        <span>
          <label>Add a Label to your task</label>
          
          {props.add_task_data.map(task => {
           <select onChange={handleChangeLabel} name="task-label">
             <option>{task}</option>
           </select>
          })}
         
        </span>
      </form>
      </>
  );       
      

  
  
}

2

2 Answers

0
votes

In parent when you are passing data to child, you are passing <Label {...add_task_data.title}/> which means you are passing only title but in child class you are trying to map whole data which you don't have. so instead pass whole of the dataset like <Label {add_task_data}/>.

0
votes

The issue is that you are expecting, in Label.js, the prop add_task_data when you try to access to it:

export default function Label(props){
  
  // ...

  return (
    // ...
          // will throw when "add_task_data" prop value is *undefined*
          {props.add_task_data.map(task => {
             // ...
          })}
    // ...
  );
}

Then, in App.js, when you instantiate the component:

              <Label {...add_task_data.title}/>

you are not passing the add_task_data expected prop. In this case, you are deconstructing the spread of add_task_data.title which is a string, which doesn't seem to be making sense for your current scenario.

A solution to your issue, which I believe is what you were intending to do, would be just instantiating Label as:

              <Label {...add_task_data}/>