0

I am coding a react app in which a user can click a button to swap an item in an array with the item to its left. I wrote a function to implement this without mutating the original items array that is rendering on the page, but this function is not doing anything to my code, nor is it returning any errors.

Here is my app component, which defines the function swapLeft then passes that function down to the Item component as props:

import React, { useState } from "react";
import Form from "./components/Form";
import Item from "./components/Item";
import { nanoid } from "nanoid";
import './App.css';

function App(props) {
  const [items, setItems] = useState(props.items);

  function deleteItem(id) {
    const remainingItems = items.filter(item => id !== item.id);
    setItems(remainingItems);
  }

  function swapLeft(index) {
    const index2 = index - 1;
    const newItems = items.slice();
    newItems[index] = items[index2];
    newItems[index2] = items[index];
    return newItems;
  }

  const itemList = items
  .map((item, index) => (
    <Item
      id={item.id}
      index={index}
      name={item.name}
      key={item.id}
      deleteItem={deleteItem}
      swapLeft={swapLeft}
    />
  ));


  function addItem(name) {
    const newItem = { id: "item-" + nanoid(), name: name };
    setItems([...items, newItem]);
  }


  return (
    <div className="form">
      <Form addItem={addItem} />
      <ul className="names">
        {itemList}
      </ul>
    </div>
  );
}

export default App;

And the Item component:

import React from "react";
import {  Button, Card, CardContent, CardHeader } from 'semantic-ui-react'

export default function Item(props) {
    return (
        
      <Card>
        <CardContent>
         <CardHeader> {props.name}</CardHeader>
          <Button onClick={() => props.deleteItem(props.id)}>
            Delete <span className="visually-hidden"> {props.name}</span>
          </Button>
          </CardContent>
          <CardContent style={{ display: 'flex' }}>
             <i className="arrow left icon" onClick={() => props.swapLeft(props.index)} style={{ color: 'blue'}}></i>
            <i className="arrow right icon"  style={{ color: 'blue'}}></i>
           </CardContent>
        </Card>
        
    );
  }

Is there a better way for me to write this function and implement this? I suppose I could do something with the React setState hook, but this seemed like an easier solution. I am new to React so any insight would be helpful

4
  • please check swapLeft, it is wrong. you need to save 1 value in temp let temp = index[index]; newItems[index] = items[index2]; newItems[index2] = temp; Commented Sep 20, 2021 at 16:14
  • If you are looking to swap the elements and this swap is visible to the user without mutating items, you cant (unless you created another state variable to preserve the swapped array) Commented Sep 20, 2021 at 16:18
  • Hi there, I run into the same problem. This is the function I wrote with your edits: function swapLeft(index) { let temp = index[index]; let index2 = index - 1; const newItems = items.slice(); newItems[index] = items[index2]; newItems[index2] = temp; return newItems; } Commented Sep 20, 2021 at 16:21
  • @ZouhairDre okay I see. I will work on making another state variable to preserve the swapped array Commented Sep 20, 2021 at 16:21

2 Answers 2

2

The way React knows if the state has changed is whether the state is refers to an entirely different address in memory. In case of arrays, if you want React to rerender the page because the array in the state changed, you need to provide it an entirely new array. Modifying the existing array will not trigger the render process.

Basically, what you need to do is changed the last line of swapLeft function to

setItems(newItems)

If you want the changes to take effect immediately (which is what I guess you want to do here)

You can also use the return value from the function and change the state in another component, FYI.

EDIT:

I looked at this again, and your implementation of swap is also wrong, but even if you corrected it you still wouldn't see a change, unless you did what I mentioned above

The full correct function would be

 function swapLeft(index) {
    const index2 = index - 1;
    const newItems = items.slice();
    const temp = items[index];
    newItems[index] = items[index2];
    newItems[index2] = temp;
    setItems(newItems);
  }

Sign up to request clarification or add additional context in comments.

2 Comments

There was actually another problem I missed in the code, I edited my answer
Saw it. Thanks!!!
0

Just to maybe clarify the previous one. If you don't call setState, your component doesn't rerender. This means that no matter what you do with those arrays, it won't be visible on the screen.

2 Comments

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
Got it. Thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.