Phương thức đẩy trong React Hooks (useState)?


112

Làm thế nào để đẩy phần tử vào trong mảng useState React hook? Đó có phải là một phương pháp cũ trong trạng thái phản ứng? Hay một cái gì đó mới?

Ví dụ: ví dụ về setState push ?

Câu trả lời:


271

Khi sử dụng useState, bạn có thể nhận được phương thức cập nhật cho mục trạng thái:

const [theArray, setTheArray] = useState(initialArray);

sau đó, khi bạn muốn thêm một phần tử mới, bạn sử dụng hàm đó và truyền vào mảng mới hoặc một hàm sẽ tạo mảng mới. Thông thường là cái sau, vì các bản cập nhật trạng thái là không đồng bộ và đôi khi theo đợt:

setTheArray(oldArray => [...oldArray, newElement]);

Đôi khi bạn có thể thoát mà không cần sử dụng biểu mẫu gọi lại đó, nếu bạn chỉ cập nhật mảng trong trình xử lý cho một số sự kiện người dùng cụ thể như click(nhưng không giống như mousemove):

setTheArray([...theArray, newElement]);

Các sự kiện mà React đảm bảo rằng kết xuất được tuôn ra là "các sự kiện rời rạc" được liệt kê ở đây .

Ví dụ trực tiếp (chuyển một cuộc gọi lại vào setTheArray):

Bởi vì bản cập nhật duy nhất theArraytrong đó là bản trong một clicksự kiện (một trong những sự kiện "rời rạc"), tôi có thể nhận được bản cập nhật trực tiếp trong addEntry:


1
... và thử setTheArray(currentArray => [...currentArray, newElement])nếu cách trên không hoạt động. Nhiều khả năng trong useEffect(...theArray..., []), điều quan trọng là nhận ra rằng theArraylà một hằng số, vì vậy thông tin cập nhật chức năng là cần thiết cho các giá trị từ tương lai ám
Aprillion

@Aprillion - Không chắc bạn đang nói gì với useEffectví dụ đó ...?
TJ Crowder

1
Nếu useEffectcó một danh sách phụ thuộc trống [], nó sẽ chỉ được thực thi trong lần hiển thị đầu tiên. Vì vậy, giá trị của theArraybên trong hiệu ứng sẽ luôn là initialArray. Trong các tình huống setTheArray([...initialArray, newElement])không có ý nghĩa và khi theArrayhằng số luôn bằng initialValue, thì cần cập nhật chức năng.
Aprillion

@Aprillion - Tôi e rằng mình vẫn chưa hiểu, có thể hơi đặc. :-) Tại sao bạn cần một hiệu ứng chỉ với giá trị mảng ban đầu ? (Ý tôi là, có thể có trường hợp sử dụng không thường xuyên, nhưng ...) Và ngay cả khi bạn làm vậy, nó có liên quan gì đến câu hỏi?
TJ Crowder

Xin chào @TJCrowder, tôi đang sử dụng cách gọi lại để hợp nhất dữ liệu cũ với dữ liệu mới khi tìm nạp dữ liệu, nhưng vì lý do nào đó mà nó hoạt động không bình thường, bạn có thể vui lòng kiểm tra điều này để hiểu vấn đề của tôi không?
Oliver D

46

Để mở rộng thêm một chút, đây là một số ví dụ phổ biến. Bắt đầu với:

const [theArray, setTheArray] = useState(initialArray);
const [theObject, setTheObject] = useState(initialObject);

Đẩy phần tử vào cuối mảng

setTheArray(prevArray => [...prevArray, newValue])

Đẩy / cập nhật phần tử ở cuối đối tượng

setTheObject(prevState => ({ ...prevState, currentOrNewKey: newValue}));

Đẩy / cập nhật phần tử ở cuối mảng đối tượng

setTheArray(prevState => [...prevState, {currentOrNewKey: newValue}]);

Đẩy phần tử vào cuối đối tượng của mảng

let specificArrayInObject = theObject.array.slice();
specificArrayInObject.push(newValue);
const newObj = { ...theObject, [event.target.name]: specificArrayInObject };
theObject(newObj);

Đây cũng là một số ví dụ làm việc. https://codesandbox.io/s/reacthooks-push-r991u


4
Cảm ơn bạn cho tất cả các ví dụ. Điều chính xác mà tôi đang gặp phải là phần tử Đẩy của bạn ở cuối đối tượng của mảng . Tôi đã thử rất nhiều thứ khác nhau, nhưng không thể kết hợp được.
sdouble

5

Tương tự như cách bạn làm với trạng thái "bình thường" trong các thành phần lớp React.

thí dụ:

function App() {
  const [state, setState] = useState([]);

  return (
    <div>
      <p>You clicked {state.join(" and ")}</p>
      //destructuring
      <button onClick={() => setState([...state, "again"])}>Click me</button>
      //old way
      <button onClick={() => setState(state.concat("again"))}>Click me</button>
    </div>
  );
}

điều này sẽ làm việc với onClick, nhưng setstate (oldState => [... oldState, pushsomething]) là cách bạn nên làm điều đó
Cyrus Zei

3
// Save search term state to React Hooks with spread operator and wrapper function

// Using .concat(), no wrapper function (not recommended)
setSearches(searches.concat(query))

// Using .concat(), wrapper function (recommended)
setSearches(searches => searches.concat(query))

// Spread operator, no wrapper function (not recommended)
setSearches([...searches, query])

// Spread operator, wrapper function (recommended)
setSearches(searches => [...searches, query])

https://medium.com/javascript-in-plain-english/how-to-add-to-an-array-in-react-state-3d08ddb2e1dc


2

setTheArray([...theArray, newElement]);là câu trả lời đơn giản nhất nhưng hãy cẩn thận đối với sự đột biến của các mục trong Array . Sử dụng nhân bản sâu các mục mảng.


Nhân bản sâu mà bạn đề cập, nó có nghĩa là nhận dưới dạng objA. UseState và nối objA với objB? Giống như liên kết này? gist.githubusercontent.com/kahsing/…
Luiey

1

Phương pháp được đề xuất nhiều nhất là sử dụng hàm wrapper và toán tử spread cùng nhau. Ví dụ: nếu bạn đã khởi tạo một trạng thái có tên namenhư thế này,

const [names, setNames] = useState([])

Bạn có thể đẩy sang mảng này như thế này,

setNames(names => [...names, newName])

Hy vọng rằng sẽ giúp.


Vui lòng không đăng câu trả lời chỉ có liên kết. Liên kết có thể bị hỏng trong tương lai. Thay vào đó, hãy viết một phần của bài báo đó và đảm bảo rằng bạn thực sự trả lời câu hỏi.
BlackCetha

Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi. - Từ đánh giá
ilke444

0

Tôi đã thử các phương pháp trên để đẩy một đối tượng vào một mảng đối tượng trong useState nhưng đã gặp lỗi sau khi sử dụng TypeScript :

Nhập 'TxBacklog [] | undefined 'phải có một phương thức' Symbol.iterator 'trả về một iterator.ts (2488)

Thiết lập cho tsconfig.json rõ ràng là đúng:

{
   "compilerOptions": {
   "target": "es6",
   "lib": [
      "dom",
      "dom.iterable",
      "esnext",
      "es6",
],

Cách giải quyết này đã giải quyết được vấn đề (mã mẫu của tôi):

Giao diện:

   interface TxBacklog {
      status: string,
      txHash: string,
   }

Biến số đưa ra:

    const [txBacklog, setTxBacklog] = React.useState<TxBacklog[]>();

Đẩy đối tượng mới vào mảng:

    // Define new object to be added
    const newTx = {
       txHash: '0x368eb7269eb88ba86..',
       status: 'pending'
    };
    // Push new object into array
    (txBacklog) 
       ? setTxBacklog(prevState => [ ...prevState!, newTx ])
       : setTxBacklog([newTx]);

0

nếu bạn muốn đẩy sau chỉ mục cụ thể, bạn có thể làm như sau:

   const handleAddAfterIndex = index => {
       setTheArray(oldItems => {
            const copyItems = [...oldItems];
            const finalItems = [];
            for (let i = 0; i < copyItems.length; i += 1) {
                if (i === index) {
                    finalItems.push(copyItems[i]);
                    finalItems.push(newItem);
                } else {
                    finalItems.push(copyItems[i]);
                }
            }
            return finalItems;
        });
    };
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.