Home > Enterprise >  Generate a new item in an array in React?
Generate a new item in an array in React?

Time:06-17

I'm building a to-do list and I want each list item to have a number, starting from 1. I'm using the useState hook on the counter but I can't figure out how to add new items to the array every time I click on a button. I haven't coded in months and I'm really rusty.

function Product() {
  const [input, setInput] = useState("");
  const [todo, setTodo] = useState([]);
  const [count, setCount] = useState([]);

  const addTodo = e => {
    e.preventDefault();

    setTodo([...todo, input]);
    setCount(prevCount => [...prevCount, prevCount   1]);

    setInput("");
  };

  return (
    <div>
      <form>
        <input value={input} onChange={e => setInput(e.target.value)} type='text' />
        <button type='submit' onClick={addTodo}>
          Add!
        </button>
      </form>

      <h2 style={{ marginBottom: "0.5rem" }}>List of To-dos !</h2>

      {todo.map(todo => (
        <p>
          {count.map(count => (
            <p>{count}</p>
          ))}
          {todo}
        </p>
      ))}
    </div>
  );
}

I want to make it so each time I add a list item, it adds its number to the left. The first item would have 1, the second 2, etc..

CodePudding user response:

This is really bad practice:

What you want to do is use the index param that Javascript map function gives you:

Good practice

todo.map((todo, index) => (
    <p>{index} - {todo}</p>
))

Output

0 - walk dog
1 - do yoga

Now if want the index to start at 1, you can simply add 1 to index

todo.map((todo, index   1) => (
    <p>{index} - {todo}</p>
))

Output

1 - walk dog
2 - do yoga

Since the index values are unique, you could use that to your benefit when performing other actions such as deleting etc. Usually you add the key attribute to the individual child values according to the official React documentation as follows

todo.map((todo, index   1) => (
    <p key={index   1}>{index} - {todo}</p>
))

where key is a unique value.

Also, change your variable names to something more meaningful. I'd suggest changing todo to plurial todos.

Your final code should look like this:

function Product() {
  const [input, setInput] = useState("");
  const [todo, setTodo] = useState([]);

  const addTodo = e => {
    e.preventDefault();

    setTodo([...todo, input]);

    setInput("");
  };

  return (
    <div>
      <form>
        <input value={input} onChange={e => setInput(e.target.value)} type='text' />
        <button type='submit' onClick={addTodo}>
          Add!
        </button>
      </form>

      <h2 style={{ marginBottom: "0.5rem" }}>List of To-dos !</h2>

      {todo.map((count, index   1) => (
          <p key={index   1}>{index} {todo}</p>
      ))}
    </div>
  );
}

CodePudding user response:

Don't.

There's no reason to track the count of items in an array as its own separate state value.

  1. Arrays have a length property which tells you the count of items in the array.
  2. .map() includes an index in the callback, so if you just want to output the array index then you can do that.
  3. You certainly don't need an array of numbers from 1-X in order to know the numbers from 1 to X. The value of X alone gives you this information.

Remove the count state value entirely, and just output the index of the array from the todo list:

{todo.map((t, x) => (
  <p>
    {x}
    {t}
  </p>
))}

Note also that I abbreviated your inner todo variable to just t. You can call it whatever you like, but giving it the same name as another variable you already have is just asking for confusion and bugs.

You may instead want to rename your array to something plural, like todos. Then each item therein is semantically a todo:

{todos.map((todo, x) => (
  <p>
    {x}
    {todo}
  </p>
))}

Basically, names are important. A variable/type/property/etc. name should tell you exactly and unambiguously what it is. Poor variable names lead to confusing code, and being confused about your code is exactly what brought you here.

  • Related