Upon rerender, React fails to refresh the style changes

I am encountering an issue with my React component where the visibility and position can be changed by the user.

Currently, the visibility can be toggled by adding or removing a CSS class, while the position is adjusted through a function that updates the top and left values after a Drag & Drop interaction.

The problem arises when React fails to update the style upon rerendering the component for visibility changes.

class MoveableCard extends React.Component {
    ...
    render() {
        ...
        return <div className={(this.props.isVisible ? '' : 'hide')}
                    draggable="true" onDragStart={dragStart}
                    style={{top:'initial', left:'initial'}}>
            ...
        </div>
    }
}



function dragStart(event) {
    var style = window.getComputedStyle(event.target, null)
    event.dataTransfer.setData("text/plain", JSON.stringify({
        id:event.target.getAttribute('data-reactid'),
        x:(parseInt(style.getPropertyValue("left"),10) - event.clientX),
        y:(parseInt(style.getPropertyValue("top"),10) - event.clientY)
    }))
}
function dragOver(event) {
    event.preventDefault()
    return false
} 
function drop(event) {
    let data = JSON.parse(event.dataTransfer.getData("text/plain"))
    let el = document.querySelectorAll("[data-reactid='" + data.id + "']")[0]

    el.style.left = (event.clientX + parseInt(data.x, 10)) + 'px'
    el.style.top = (event.clientY + parseInt(data.y, 10)) + 'px'

    event.preventDefault()
    return false
}
document.body.addEventListener('dragover',dragOver,false)
document.body.addEventListener('drop',drop,false)

Initially, the Card's style shows

style="top: initial; left: initial;"
.

After being moved, the style changes to style="top: 162px; left: 320px;".

However, when the Card is hidden using the class hide, the style remains the same style="top: 162px; left: 320px;", despite attempts to reset it.

I am looking for a solution to force React to update the style accordingly or explore alternative methods to achieve this functionality.

Answer №1

Summary:

Utilize inner state and the component lifecycle for handling event functions.

Detailed Explanation:

It is advisable to place event handlers within the component itself rather than using global methods. Here is an example of setting up event handlers inside a React component:

class MoveableCard extends React.Component {
  dragStart(event) {}
  dragOver(event) {}
  drop(event) {}
}

To ensure proper binding of 'this' context in the component, you can bind the event handler functions in the constructor or use arrow functions within the render method:

constructor() {
  this.dragStart = this.dragStart.bind(this);
  this.dragOver = this.dragOver.bind(this);
  this.drop = this.drop.bind(this);
}

In order to update or re-render the component, you should modify its inner state. Initialize the state with default values during componentWillMount:

componentWillMount() {
  this.state = { top: 0, left: 0 };
}

Within the event handlers, update the top and left properties on the inner state using this.setState, which will trigger a re-render:

drop() {
   // Assuming you have set this.left and this.top in the dragOver method
   this.setState({ top: this.top, left: this.left });
}

After updating the state, you can access the updated values in your render method like this:

render() {
  return (
    <div className={(this.props.isVisible ? '' : 'hide')}
         draggable="true"
         onDragStart={this.dragStart}
         style={{top: this.state.top, left: this.state.left}}>
    </div>
  );
}

Answer №2

After considering the insights provided by Andrew, dejakob, and Chris, I have managed to come up with a solution - a big thank you to all of you :)

Initially, I was under the impression that I couldn't move the Functions into the Component because the Drop Event with the final position was emitted by the element where I dropped my Card, not by the Card itself.

However, I discovered a dragend Event that is emitted by the Card itself and contains the position information.

Using this event, I could easily set the position in the state (and remove it via a ref to unsetPosition in the parent component).

class MoveableCard extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            styles: {top:'initial', left:'initial'}
        }
        this.drop = this.drop.bind(this);
    }

    dragStart(e) {
        let style = window.getComputedStyle(e.target, null)

        this.setState({l: parseInt(style.getPropertyValue("left")) - e.clientX, y: parseInt(style.getPropertyValue("top")) - e.clientY})
    }

    drop(e) {
        this.setState({left: this.state.l + e.clientX, top: this.state.y + e.clientY})

        e.preventDefault()
        return false
    }

    unsetPosition() {
       this.setState({styles: {top:'initial', left:'initial'}})
    }

    render() {
        return <div className={(this.props.isVisible ? '' : 'hide')}
                    draggable="true"
                    onDragStart={this.dragStart}
                    onDragEnd={this.drop}
                    style={this.state.styles}>
            ...
        </div>
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Bootstrap 3 Full-Width Responsive Image Overlapping

I have designed a grid layout with col-md-7 on the left side and col-md-5 on the right side. The images in the col-md-5 are responsive and have a full-width of col-md-12. <div class="container"> <div class="row"> <div class="col ...

Interactive Bar chart updates in real-time with Highcharts and AngularJs

With the help of a sample from Highcharts (here), I successfully integrated a bar chart into AngularJs. Below is the HTML code: <!DOCTYPE html> <html ng-lang="en" ng-app="myModule"> <head> <meta charset="ISO-8859-1"> <script sr ...

Next.js encountered an error while trying to locate the flowbite.min.js file for Tailwindcss and Flowbite, resulting in a

I'm having an issue with integrating the flowbite package with TailwindCSS in my Next.js application. Despite configuring everything correctly, I am encountering an error when adding the flowbite.min.js script: GET http://localhost:3000/node_modules/f ...

Error: The function theme.spacing is not recognized as a valid function

I'm currently developing a React application using Material-UI version 5, and I've encountered an issue where theme.spacing is not functioning as expected. import { makeStyles } from "@material-ui/styles"; import React from "react& ...

How can I make Material UI's grid spacing function properly in React?

I've been utilizing Material UI's Grid for my layout design. While the columns and rows are functioning properly, I've encountered an issue with the spacing attribute not working as expected. To import Grid, I have used the following code: ...

Interact with concealed form using Semantic UI React reveal feature

I am using Semantic UI React's Reveal component with two different Cards - one visible and the other hidden. The hidden Card contains a form and button that I need to interact with. Is there an easy way to make the form accessible, or do I need to fin ...

Error: The function this.state.patients.map is not iterable

I recently started learning React JS and I'm working on building a React application. However, I've encountered an issue with the mapping function: Below is my code snippet where I attempt to render the data: class Patients extends Component ...

Guide to centering a list on a webpage using Bootstrap 3

Looking to create a centered list using the latest version of Bootstrap 3. Any tips? The desired list should be positioned in the middle of the page. ___________________________________________ | | | ...

React: Error Caused by Invariant Violation (minus table)

After researching on Stack Overflow, I found that most solutions involving <table> and <tbody>, but my issue is unrelated to that. To render the component <GISMapDropdownMenu>, I utilized the ScriptjsLoader from the react-google-maps lib ...

What other options are available for achieving the same functionality as FormData.delete() given its low level of support?

When building my website, I utilized the FormData.delete() method to exclude specific form fields before sending data to the server. However, I encountered a setback as this method is not supported on various browsers, including Safari. Therefore, I am in ...

The functionality of the button in my script is limited to a single use

Below is a simple code snippet that I wrote: HTML & CSS: <!DOCTYPE html> <html> <head> <title> JavaScript Console </title> <style> button { text-align:center; ...

What is the best way to direct the next input focus when pressing Enter in ReactJS?

I have a TextField component from MaterialUI in my ReactJS project. I want to set focus on the next field when the enter key is pressed on a Google Keyboard. Can anyone guide me on how to achieve this functionality? ...

What steps do I need to take to ensure the CSS hover effect functions properly?

After conducting a simple test underneath the main divs, I found that it works as intended. However, the primary one is not functioning properly. I attempted to apply the class "services-icon" to the div containing the image, but it still did not work. I ...

Guide to creating dependent form fields in ReactJS

I am currently working on developing an application similar to peer-to-peer lending platforms. To give you a better idea, here is a screenshot: Lending Application My goal is to dynamically link the input field for loan amount with a slider, so that they ...

Solution for displaying as a table cell in Internet Explorer 6 and 7: Workaround

I am currently working on creating a single-row CSS table with multiple cells, aiming to vertically center text within each cell. The desired table layout is as follows: <table width="100%" height="54" border="0" bgcolor="red"> <tr> <t ...

Having two identical select2 forms on the same page

Integrating two select2 multi-value select boxes into my Rails application is proving to be a challenge. While the top form functions correctly, the bottom one refuses to work as expected. Despite my attempts at changing IDs and adding new JavaScript cod ...

How can I ensure that a particular component type passes the typescript check in a react-typescript project?

I'm fairly new to using TypeScript, although I have a lot of experience with React (and prop-types). Recently, I've run into an issue when it comes to typing my components, specifically when another component is passed as a prop. I already have ...

Module gulp.js not found

After retrieving a solution from TFS, I encountered an error in my console while attempting to clean and build the solution - Error: Cannot find module 'C:..\node_modules\gulp\bin\gulp.js'. Any thoughts on why it is not being ...

Tips for utilizing a for loop within an array extracted from a jQuery element for automation

I am looking to streamline the process using a for loop for an array containing 10 image files in the parameters of initialPreview and initialPreviewConfig. My envisioned solution involves the following code snippet: for (i = 0; i < 11; i++) { "< ...

Guide to creating intricate designs on an HTML5 Canvas, one pixel at a time

Imagine a scenario where there is a 900x900 HTML5 Canvas element involved. In this case, there is a function named computeRow, which takes the row number as a parameter and returns an array of 900 numbers. These numbers represent colors ranging from 0 to ...