简体   繁体   English

反应:如何只为一个元素更新 state,而不是批量更新

[英]React: How to update state for just one element, rather than batch update

I am a beginner with React.我是 React 的初学者。 I have a project I'm working on with some sample travel tours.我有一个项目,我正在做一些示例旅行。 I would like to use a "read more/show less" feature for the description of each tour.我想使用“阅读更多/显示更少”功能来描述每次旅行。 The read more/show less button is toggling, but it's showing more or less description for all of the tours when clicked, when I want it to just toggle the tour that's clicked.阅读更多/显示更少按钮正在切换,但是当我希望它仅切换单击的游览时,它会在单击时显示所有游览的或多或少的描述。 In other words, it's updating the state for ALL tours, rather than just the one that's clicked.换句话说,它正在为所有旅行更新 state,而不仅仅是点击的旅行。 Hopefully that makes sense.希望这是有道理的。 Please help.请帮忙。 Thanks in advance.提前致谢。

import React, { useState, useEffect } from 'react';
import './index.css';

const url = 'https://course-api.com/react-tours-project';

const Tour = () => {
    const [tourItem, setTourItem] = useState('');

    const removeItem = (id) => {
        let newList = tourItems.filter((item) => item.id !== id);
        setTourItem(newList);
    };
    const [fetchingData, setFetchingData] = useState(true);

    useEffect(() => {
        const abortController = new AbortController();
        const fetchUrl = async () => {
            try {
                const response = await fetch(url, {
                    signal: abortController.signal,
                });
                if (fetchingData) {
                    const data = await response.json();
                    setTourItem(data);
                }
                setFetchingData(false);
            } catch (e) {
                console.log(e);
            }
        };
        fetchUrl();
        return () => {
            //cleanup!
            abortController.abort();
        };
    });

    const tourItems = Object.values(tourItem);

    const [readMore, setReadMore] = useState(false);

    return (
        <>
            {tourItems.map((item) => {
                return (
                    <div key={item.id}>
                        <article className='single-tour'>
                            <img src={item.image} alt={item.name} />
                            <footer>
                                <div className='tour-info'>
                                    <h4>{item.name}</h4>
                                    <h4 className='tour-price'>
                                        ${item.price}
                                    </h4>
                                </div>
                                {readMore ? (
                                    <p>
                                        {item.info}
                                        <button
                                            onClick={() => setReadMore(false)}
                                        >
                                            Show Less
                                        </button>
                                    </p>
                                ) : (
                                    <p>
                                        {item.info.slice(0, 450) + '...'}
                                        <button
                                            onClick={() => setReadMore(true)}
                                        >
                                            Read More
                                        </button>
                                    </p>
                                )}
                                <button
                                    className='delete-btn'
                                    onClick={() => removeItem(item.id)}
                                >
                                    Not Interested
                                </button>
                            </footer>
                        </article>
                    </div>
                );
            })}
        </>
    );
};

export default Tour;

Good question!好问题! It happened because you share the readMore state with all of the tour items.发生这种情况是因为您与所有旅游项目共享readMore state。 You can fix this by encapsulating the tour items into a component.您可以通过将游览项目封装到组件中来解决此问题。

It should look something like this;它应该看起来像这样;

The component that encapsulates each tour items封装每个旅游项目的组件

import React, {useState} from "react";
import "./index.css";

const SpecificTourItems = ({item, removeItem}) => {
    const [readMore, setReadMore] = useState(false);
    return (
      <div key={item.id}>
        <article className="single-tour">
          <img src={item.image} alt={item.name} />
          <footer>
            <div className="tour-info">
              <h4>{item.name}</h4>
              <h4 className="tour-price">${item.price}</h4>
            </div>
            {readMore ? (
              <p>
                {item.info}
                <button onClick={() => setReadMore(false)}>Show Less</button>
              </p>
            ) : (
              <p>
                {item.info.slice(0, 450) + "..."}
                <button onClick={() => setReadMore(true)}>Read More</button>
              </p>
            )}
            <button className="delete-btn" onClick={() => removeItem(item.id)}>
              Not Interested
            </button>
          </footer>
        </article>
      </div>
    );
  };

  export default SpecificTourItems;

the component that fetch & maps all the tour items (your old component:))获取和映射所有旅游项目的组件(您的旧组件:))

import React, {useState, useEffect} from "react";
import SpecificTourItems from "./SpecificTourItems";

const url = "https://course-api.com/react-tours-project";

const Tour = () => {
  const [tourItem, setTourItem] = useState("");

  const removeItem = (id) => {
    let newList = tourItems.filter((item) => item.id !== id);
    setTourItem(newList);
  };
  const [fetchingData, setFetchingData] = useState(true);

  useEffect(() => {
    const abortController = new AbortController();
    const fetchUrl = async () => {
      try {
        const response = await fetch(url, {
          signal: abortController.signal,
        });
        if (fetchingData) {
          const data = await response.json();
          setTourItem(data);
        }
        setFetchingData(false);
      } catch (e) {
        console.log(e);
      }
    };
    fetchUrl();
    return () => {
      //cleanup!
      abortController.abort();
    };
  });

  const tourItems = Object.values(tourItem);

  const [readMore, setReadMore] = useState(false);

  return (
    <>
      {tourItems.map((item, key) => {
        return (
          <SpecificTourItems item={item} removeItem={removeItem} key={key} />
        );
      })}
    </>
  );
};

export default Tour;

I hope it helps, this is my first time answering question in Stack Overflow.希望对您有所帮助,这是我第一次在 Stack Overflow 中回答问题。 Thanks & Good luck!谢谢,祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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