React - JSX syntax issue, and how to iterate with map and display items on newlines

前端 未结 2 391
清酒与你
清酒与你 2021-01-27 09:27

I\'m a React noob and making a ToDo list style Recipe List app. I have a functional component, Item.js, and I am using JSX and the map function to iterate through each recipe it

相关标签:
2条回答
  • 2021-01-27 10:12

    Here is the working version.

    class App extends React.Component {
      state = {
        items: [ "Pumpkin Pie", "Spaghetti", "Onion Pie" ],
        ingredients: [
          [ "Pumpkin Puree", "Sweetened Condensed Milk", "Eggs", "Pumpkin Pie Spice", "Pie Crust" ],
          [ "Noodles", "Tomatoe", "Sauce", "Meatballs" ],
          [ "Onion", "Pie Crust" ],
        ],
      }
    
      render() {
        return (
          <div className="box">
            <Item items={this.state.items} ingredients={this.state.ingredients} />
          </div>
        );
      }
    }
    
    const Item = props => (
      <div>
        <div className="Recipe-Item-Container" key={props.text}>
    
          {props.items.map( ( item, index ) => (
            <div className="Recipe-Item" key={item}>
    
              <h3>{item}</h3>
              <ul>
                {
                  props.ingredients[ index ].map( ingredient =>
                    <li key={ingredient}>{ingredient}</li> )
                }
              </ul>
    
    
              <div className="buttons-container">
                <button className="edit-button" onClick={() => props.edit( item, index )}>Edit</button>
                <button className="delete-button" onClick={() => props.delete( item, index )}>Delete</button>
              </div>
    
            </div>
          ) )}
        </div>
      </div>
    );
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="root"></div>

    But if I were you I would change my state shape. Something like that:

    class App extends React.Component {
      state = {
        items: [
          {
            name: "Pumpkin Pie",
            ingredients: [
              "Pumpkin Puree",
              "Sweetened Condensed Milk",
              "Eggs",
              "Pumpkin Pie Spice",
              "Pie Crust"
            ]
          },
          {
            name: "Spaghetti",
            ingredients: ["Noodles", "Tomatoe", "Sauce", "Meatballs"]
          },
          {
            name: "Onion Pie",
            ingredients: ["Onion", "Pie Crust"]
          }
        ]
      };
    
      removeItem = item => {
        const newItems = this.state.items.filter(el => el.name !== item.name);
        this.setState({ items: newItems });
      };
    
      editItem = item => alert(`${item.name} will be edited`);
    
      renderItems = () =>
        this.state.items.map(item => (
          <Item
            key={item.name}
            item={item}
            removeItem={this.removeItem}
            editItem={this.editItem}
          />
        ));
    
      render() {
        return <div className="box">{this.renderItems()}</div>;
      }
    }
    
    const Item = props => {
      const { item, removeItem, editItem } = props;
      const handleRemove = () => removeItem(item);
      const handleEdit = () => editItem(item);
    
      return (
        <div>
          <div className="Recipe-Item-Container" key={props.text}>
            <div className="Recipe-Item">
              <h3>{item.name}</h3>
              <ul>
                {item.ingredients.map(ingredient => (
                  <li key={ingredient}>{ingredient}</li>
                ))}
              </ul>
              <div className="buttons-container">
                <button className="edit-button" onClick={handleEdit}>
                  Edit
                </button>
                <button className="delete-button" onClick={handleRemove}>
                  Delete
                </button>
              </div>
            </div>
          </div>
        </div>
      );
    };
    
    ReactDOM.render(<App />, document.getElementById("root"));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
    <div id="root"></div>

    Changes

    • State shape: Instead of holding two arrays, we are keeping an object per item. This object has a name and ingredients property. Maybe in the future, it may have a unique id? Objects are flexible.
    • Instead of passing all the items to an Item component, we are mapping the items in the parent component and pass just one item to the Item component.
    • We still have handler functions defined in the parent. But, we are not using them directly in the button's callback with an arrow function. So, they are not recreated in every render. Also, we don't have to use an index to pass the items back to the parent. We have the item prop itself! You can see how we handle the remove functionality: with .filter You can apply the same functionality to other functions. .map, .filter, Object.assign or spread syntax are all good tools. Just, avoid mutating your state directly.
    0 讨论(0)
  • 2021-01-27 10:26

    If you add curly braces after the fat arrow, you will have to explicitly return the JSX.

    const Item = (props) => (
      <div>
        <div className="Recipe-Item-Container" key={props.text}>
    
          {props.items.map((item, index) => {
              return (
                  <div className="Recipe-Item" key={index}>
    
                  <h3>{item}</h3>
    
                  <p className="ingredients-list">
                       {props.ingredients[index].map((ingredient, ingredientIndex) => {
                          return (
                               <div className="ingredient" key={ingredient}>
                                   {ingredient}
                               </div>
                         )
                       }}
                  </p>
    
                  <div className="buttons-container">
                    <Button className="edit-button" onClick={() => props.edit(item, index)}>Edit</Button>
                    <Button className="delete-button" onClick={() => props.delete(item, index)}>Delete</Button>
                  </div>
    
                </div>
              )
            }
          )}
        </div>
      </div>
    )
    
    0 讨论(0)
提交回复
热议问题