Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use map function for hooks useState properties

I tried to use map function for looping my list data in react-hooks useState but I stuck with an error that "TypeError: Cannot read property 'map' of undefined"

//1.Initial declaration
const App = props=>  {
const [state, changeState]= useState ({
    name:"",
    eventTitle:"",
    details:"",
    objdata:{},
    list:[],
    toggleIndex:"",
    editName: "",
    editEventTitle: "",
    editDetails: "",
    editObj: {}
});


//2.logic comes here


//3.tried using map


{(state.list.map((data,id)=>{
console.log ('loop data',data)
}))}

enter image description here

like image 966
Little_Programmer Avatar asked Sep 12 '25 20:09

Little_Programmer


1 Answers

As we suspected you are not setting your state in the right way. I tried to explain in my comment, with hooks when you set your state it does not merge the updated properties with the current one. So, you should think about that. Right now you are setting your state like that:

const handleName = name => {
  changeState({
    name: name.target.value
  });
};

Here, you are setting the name property and lose other parts of your state. Hence, when you set your state, you lose list as well as other parts of your state. This is how you should do it:

const handleName = name => {
  const { target } = name;

  changeState(state => ({
    ...state,
    name: target.value,
  }));
};

You take the old state, keep the other properties by spreading it, then update the relevant part. I would use here event instead of name. It is not "name", it is "event" after all actually :)

const handleName = event => {
  const { target } = event;

  changeState(state => ({
    ...state,
    name: target.value,
  }));
};

Also, you have a few other problems and unnecessary parts in your code. For example, you are struggling too much to handle the submit and add an object to your list. You don't need an extra objdata in your state to push it to the list. If you want to construct an extra object, you can do it in the function itself.

Here is a very simple way to do it:

const submitHandle = () => {
  const { name, eventTitle, details } = state;
  const obj = { name, eventTitle, details };

  changeState(state => ({
    ...state,
    list: [ ...state.list, obj ],
  }))
};

Again, we are using spread operator to keep both the other parts of the state and while updating the list, to keep other objects. Do not set your state as you do in your submitHandle function. Try to think it simple :)

Also, you don't need to bind your functions when it is not necessary. You can find a working copy of the code below. I just removed unnecessary parts and fix the issues.

import React, { useState } from "react";
import ReactDOM from "react-dom";

const App = props => {
  const [state, changeState] = useState({
    name: "",
    eventTitle: "",
    details: "",
    list: [],
    toggleIndex: "",
    editName: "",
    editEventTitle: "",
    editDetails: "",
    editObj: {}
  });

  const handleName = event => {
    const { target } = event;

    changeState(state => ({
      ...state,
      name: target.value
    }));
  };

  const handleEventTitle = event => {
    const { target } = event;

    changeState(state => ({
      ...state,
      eventTitle: target.value
    }));
  };

  const handleDetails = event => {
    const { target } = event;

    changeState(state => ({
      ...state,
      details: target.value
    }));
  };

  const submitHandle = () => {
    const { name, eventTitle, details } = state;
    const obj = { name, eventTitle, details };

    changeState(state => ({
      ...state,
      list: [...state.list, obj]
    }));
  };

  const resetHandle = () =>
    changeState(state => ({
      ...state,
      name: "",
      eventTitle: "",
      details: ""
    }));

  return (
    <div>
      <div className="jumbotron jumbotron-fluid">
        <div className="container">
          <h1 className="display-5 text-center">Let's set your reminders</h1>
        </div>
      </div>
      <div className="bg-dark container-fluid">
        <div className="row">
          <div className="col-sm-12 col-md-4 col-lg-4 " />

          <div className="col-sm-12 col-md-4 col-lg-4 ">
            <div className="card login-card ">
              <div className=" card-header ">
                <h3 className="text-center"> TO-DO LIST FORM</h3>
              </div>

              <div className="card-body">
                <form className="form-elements">
                  <input
                    value={state.name}
                    className="form-control form-inputs form-elements"
                    type="text"
                    onChange={handleName}
                    placeholder="user name"
                  />
                  <input
                    value={state.eventTitle}
                    className="form-control form-inputs form-elements"
                    type="text"
                    onChange={handleEventTitle}
                    placeholder="Event Title"
                  />
                  <input
                    value={state.details}
                    className="form-control form-inputs form-elements"
                    type="text"
                    onChange={handleDetails}
                    placeholder="Details "
                  />
                </form>
              </div>

              <div className="card-footer ">
                <button
                  type="submit"
                  onClick={submitHandle}
                  className="btn-primary offset-lg-1 offset-md-0 btn-sm "
                >
                  Create
                </button>

                <button
                  type="reset"
                  onClick={resetHandle}
                  className="btn-primary offset-lg-5 offset-md-0 btn-sm"
                >
                  cancel
                </button>
              </div>
            </div>
          </div>
          <div className="col-sm-12 col-md-4 col-lg-4 " />
        </div>

        <div className="container-fluid bg-dark">
          <div className="row ">
            {state.list.map(data => (
              <div style={{ border: "1px black solid" }}>
                <p>{data.name}</p>
                <p>{data.eventTitle}</p>
                <p>{data.details}</p>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div
        className="footer footer-copyright"
        style={{ background: "#e9ecef" }}
      >
        <div className="container">
          <h6 className=" text-center">Just make it work ;)</h6>
        </div>
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
like image 188
devserkan Avatar answered Sep 14 '25 12:09

devserkan