Gotey
Gotey

Reputation: 639

State not updating when I use it within a function

I declare a state:

  const [list, setList] = useState([]);

Then I set it within a useEffect:

  useEffect(() => {

      axios
        .post("/myroute.json", { id: selectedHotel })
        .catch(function (error) {
          console.log(error);
        })
        .then((response) => {

          console.log("is updating photo list",response.data.photos)
          setThumbs(renderThumbs(response.data.photos))
          setList(response.data.photos)

        });
  }, [selectedHotel]);







  const onDragStart = (event) => {
    // We'll access the "data-position" attribute
    // of the current element dragged
    const initialPosition = Number(event.currentTarget.dataset.position);
  
    setDragAndDrop({
      // we spread the previous content
      // of the hook variable
      // so we don't override the properties 
      // not being updated
      ...dragAndDrop, 
  
      draggedFrom: initialPosition, // set the draggedFrom position
      isDragging: true, 
      originalOrder: list // store the current state of "list"
    });
  
    console.log("within OnDrag", event.currentTarget.dataset.position, dragAndDrop, list)


     ....
    
     }

I see in the console log with in the onDragStart, "list" always remains as [] but I can see in the console log of the useEffect that response.data.photos contains what I want to set

OnDragStart is used here:


    const renderThumbs = (files) => {
      return files.map((file, index) => 
     
        {
          return(
            <li data-position={index} style={thumb} key={file.id} draggable="true" onDragStart={(ev) => onDragStart(ev)}   onDragOver={(ev) => onDragOver(ev)}  onDrop={onDrop}>
            <div style={thumbInner}>
              <img
                src={file.url}
                style={img}
              />
            </div>
            <div style={thumbCloser} onClick={removeFile(file, files)}><Emoji symbol="❌" /></div>
          </li>
          )
        }
    
      );
    }

and it's used within the use effect to set "thumbs" which is used to render the components of the list in the DOM

Upvotes: 0

Views: 49

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 282030

The problem is because of closure, since you set thee thumbs to render within state inside useEffect which is called only once, and assign the onDragStart event handler to it, you are essentially using the instance of onDragStart along with its enclosing closure when the useEffect was called for the entire lifecycle of the component. Even when the component re-render the closure is not updated since its not defined again.

What you must do is to not store the content to be rendered in state but the data that you want to use to render

useEffect(() => {

      axios
        .post("/myroute.json", { id: selectedHotel })
        .catch(function (error) {
          console.log(error);
        })
        .then((response) => {

          console.log("is updating photo list",response.data.photos)
          setThumbs(response.data.photos)
          setList(response.data.photos)

        });
  }, [selectedHotel]);

  ...

  return renderThumbs(thumbs);
 

Upvotes: 1

Related Questions