Home > database >  Re-render a function after array changes (i.e after swapping value)
Re-render a function after array changes (i.e after swapping value)

Time:10-21

I want to re-render a function after array values changes(i.e swap) but useeffect is not re-rendering it. Do not worry about the external components.Can you help me to this as i i want to add this code in my major project. I have attached the jsx and css file. In App.js file i am making a bar graph using the array and trying to re-render the bar() function after swapping the values.

import './App.css';
import "./components/Bar";
import Bar from './components/Bar';
import Footer from './components/Footer';
import Header from './components/Header';
import {useEffect} from 'react';

function App() {
  function bar(){
    return (
      arr.map((val, idx) => (
        <div
          className='element-bar'
          // key={idx}
          style={{
            height: `${val}px`,
            width: `${wid}px`,
            backgroundColor: "red",
            WebkitTransition: `background-color ${delay}ms linear`,
            msTransition: `background-color ${delay}ms linear`,
            transition: `background-color ${delay}ms linear`,
            transition: `${delay}ms`
          }} >
        </div>
      ))
    )
  }
  var arr = [10, 20, 30, 40, 50, 60];
  useEffect(() => {
    console.log(1);
    bar();
  },[arr,bar]);
  function swap(x,y){
    var t = x;
    x = y;
    y = t;
  }
  function change(){
    console.log(arr);
    swap(arr[0],arr[4]);
   }
  
  const wid = 4;
  const delay = 2;
  return (
    <div>
      <Header/>
      <button onClick={change} style={{ color: 'red' }}>Swap</button>
      <Bar/>
      <div className='array'>
        {
          bar()
        }
      </div>
      <Footer/>
    </div>
  );
}

export default App;

CSS

body {
    background-color: black;
}
.array {
    position: fixed;
    text-align: center;
    left: 250px;
    top: auto;
    bottom: 50px;
    display: flex;
    align-items: flex-end;
    flex-wrap: nowrap;
    width: 1260px;
}

.element-bar {
    display: inline-block;
    margin: 0 auto;
}

.sideNavbar {
    text-align: center;
    height: 100%;
    width: 210px;
    position: fixed;
    z-index: 1;
    top: 0;
    left: 0;
    background-color: rgb(29, 29, 29);
    overflow-x: hidden;
    padding-top: 20px;
    box-shadow: 0 4px 8px 0 rgba(81, 81, 81, 0.7), 0 6px 20px 0 rgb(81, 81, 81,0.7);
}

.sideNavbar h3 {
    font-size: 23px;
    text-decoration: underline;
    color: #818181;
    display: block;
    transition: 0.4s;
}

.sideNavbar h3:hover {
    color: #f1f1f1;
}

.sliderLabel {
    color: #f1f1f1;
}

.btn {
    margin: 10px 0;
    display: inline-block;
    padding: 6px;
    width: 100px;
    color: #818181;
    font-weight: 400;
    border: 2px solid #818181;
    background-color: transparent;
    text-transform: uppercase;
    cursor: pointer;
    border-radius: 100px;
    transition: 0.4s;
}

.btn:hover {
    color: #f1f1f1;
    border: 2px solid #f1f1f1;
    box-shadow: 0 12px 16px 0 rgba(81, 81, 81, 0.7), 0 17px 50px 0 rgba(81, 81, 81, 0.7);
    text-shadow: 0 12px 16px 0 rgba(81, 81, 81, 0.7), 0 17px 50px 0 rgba(81, 81, 81, 0.7);
}

.btndisabled {
    margin: 10px 0;
    display: inline-block;
    padding: 6px;
    width: 100px;
    border-radius: 100px;
    font-weight: 400;
    background-color: transparent;
    cursor: not-allowed;
    text-transform: uppercase;
    color: #f1f1f1;
    border: 2px solid #f1f1f1;
    box-shadow: 0 12px 16px 0 rgba(81, 81, 81, 0.7), 0 17px 50px 0 rgba(81, 81, 81, 0.7);
    text-shadow: 0 12px 16px 0 rgba(81, 81, 81, 0.7), 0 17px 50px 0 rgba(81, 81, 81, 0.7);
}

CodePudding user response:

React doesn't know that it should re render (i.e. call function which returns component tree again) when you mutate some array or any other data. To make React know about this, useState should be used. Also it better to use useCallback/useMemo to wrap all function or components which are defined in another component

// Put useState at the top of App() component
const [arr, setArr] = useState([10, 20, 30, 40, 50, 60]);
const bar = useCallback(() => {
    return (
    // ...
    )
}, [])
const swap = useCallback((x,y) => {
  var t = x;
  x = y;
  y = t;
}, [])
const change = useCallback(() => {
    console.log(arr);
    const newArr = [...arr]
    swap(newArr[0],newArr[4]);
    setArr(newArr) // This string let React know that array have been changed and components should re-render
}, [])
// ...

CodePudding user response:

Try like this

export default function App() {
  const [arr, setArr] = React.useState([10, 20, 30, 40, 50, 60])

  const swap = (item1, item2) => {
    let cloneArray = [...arr]
    const tmp = cloneArray[item1]
    cloneArray[item1] = cloneArray[item2]
    cloneArray[item2] = tmp
    setArr(cloneArray)
  }

  const wid = 4
  const delay = 2

  return (
    <div>
      <button onClick={() => swap(0, 4)} style={{ color: 'red' }}>
        Swap
      </button>
      <div className="array">
        {arr.map((val, idx) => {
          console.log(val)
          return (
            <div
              className="element-bar"
              key={idx}
              style={{
                height: `${val}px`,
                width: `${wid}px`,
                backgroundColor: 'red',
                WebkitTransition: `background-color ${delay}ms linear`,
                msTransition: `background-color ${delay}ms linear`,
                transition: `background-color ${delay}ms linear`,
                transition: `${delay}ms`
              }}></div>
          )
        })}
      </div>
    </div>
  )
}
  • Related