简体   繁体   中英

How do I create a card on button click?

I am a few days into learning React JS. It's been very interesting and simplifies JavaScript, at least how I view it. My goal at the moment is to create a button that when clicked will create a new card with a random number generated in the card.

I can't figure out how to add the onClick= functionality for it to work the way I'm envisioning it. At the moment I have the code for the button written on my index.js file. index.js is my main file, it is where my App component is located. I see people use a file named App.js, not sure why, but that's another question for later.

Currently my buttons are stylized the following way.

const App = () => {
  return (
    <body>
      <header>
        <div className="ui buttons">
          <button className="ui button mb-1 mt-1">
            <i className="plus icon"></i>
            Add Card
          </button>
          <div className="or mb-1 mt-1"></div>
          <button className="ui positive button mb-1 mt-1">
            <i className="sort numeric down icon"></i>
            Sort All
          </button>
        </div>
      </header>

They are located in a header container at the top of my page. It looks like this following image.

添加卡片或排序所有按钮标题

I want to be able to click the Add Card button and then for it to create a new card in my card container. As picture below.

带有添加卡片或排序所有按钮的卡片容器可见。

The current card you see in the above image is hard coded at the moment. I created a MainCard.js component that houses the code for the card including the functionality of the randomly generated number and the styling.

import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import { Card, Button } from "react-bootstrap";

let getRandomNumber = function (min, max) {
  let getRandom = Math.floor(Math.random() * max + min);
  return getRandom;
};

const MainCard = () => {
  return (
    <Card>
      <Button
        className="ui mini red basic icon button"
        style={{
          position: "absolute",
          top: "0",
          right: "0",
        }}
      >
        <i
          className="red x icon"
          style={{
            position: "relative",
            top: "0",
            right: "0",
          }}
        ></i>
      </Button>
      <Card.Body>{getRandomNumber(0, 101)}</Card.Body>
    </Card>
  );
};

export default MainCard;

Previously I was doing the onClick functionality in my AddCard.js but for some reason the Alert I created was both being generated when the page was being reloaded as well as when the button was clicked. I couldn't figure out the reasoning for this and it has become a wall that I haven't been able to climb over yet. I'm pretty sure I'm missing something simple, but I just can't figure out what that is. Any ideas how I can achieve this?

You need to use useState() .

For example.

import { useState } from "react";

export default function App() {
  const [{items}, setItems] = useState({ items: [] });
  const addItem = () => {
    items.push(<div key={items.length}>Hello</div>);
    setItems({ items: [...items] });
  };

  return (
    <div>
      <button onClick={addItem} />
      {items}
    </div>
  );
}

This creates a persistant storage that you can set values into that remain between component rebuilds. The object in storage has a single key "items" with an array containing the items. It is convenient to put your state in an object with a key that describes the contents. This allows you to tell what state object you are looking at if you need to debug your app.

The addItem() callback will add a new item into the object in state. Importantly, the item has a key attribute that should be unique. This helps react monitor the state of elements in an array.

You can see a demo of the above code here

As stated on Charles Bamford's response, you'll have to use the useState method. The useState method creates a variable and a method to set the value of this variable. Everytime you change a state (using it's setter) React will check the code and re-render everywhere it was used. You will need something like this:

const App = () => {
  const [cards, setCards] = useState([]); // instantiate cards as a empty Array

  const addCard = () => {
    // create a new array with the old values and the new random one
    const newCards = [...cards, Math.floor(Math.random() * 100)];

    setCards(newCards);
  };

  const removeCard = (cardIndex) => {
    // create a new array without the item that you are removing
    const newCards = cards.filter((card, index) => index !== cardIndex);

    setCards(newCards);
  };

  return (
    <body>
      <header>
        <div className="ui buttons">
          <button className="ui button mb-1 mt-1" onClick={() => addCard()}>
            <i className="plus icon"></i>
            Add Card
          </button>
          <div className="or mb-1 mt-1"></div>
          <button
            className="ui positive button mb-1 mt-1"
            onClick={() => addCard()}
          >
            <i className="sort numeric down icon"></i>
            Sort All
          </button>
        </div>
      </header>
      <main>
        {cards.map((cardNumber, index) => (
          <MainCard number={cardNumber} onRemove={() => removeCard(index)} />
        ))}
      </main>
    </body>
  );
};

With an array like this [10, 15, 33], the cards.map will do something like this for you:

  <main>
    <MainCard number={cards[0]} onRemove={() => removeCard(0)} /> // 10
    <MainCard number={cards[1]} onRemove={() => removeCard(1)} /> // 15
    <MainCard number={cards[2]} onRemove={() => removeCard(2)} /> // 33
  </main>

We are passing the "number" and the "onRemove" function from the App component to the MainCard component. Now we just have to get it from our props, like this:

const MainCard = (props) => {
  const { onRemove, number } = props

  return (
    <Card>
      <Button
        className="ui mini red basic icon button"
        style={{
          position: "absolute",
          top: "0",
          right: "0",
        }}
        onClick={() => onRemove()}
      >
        <i
          className="red x icon"
          style={{
            position: "relative",
            top: "0",
            right: "0",
          }}
        ></i>
      </Button>
      <Card.Body>{number}</Card.Body>
    </Card>
  );
};

export default MainCard;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM