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

Programmatically adjusting the color of mask images - Creative image theming

Is it possible to alter the color of an image hosted on a different website? Here is a link to an example image: Is there a technique to overlay a specific color on the image and only modify certain colors, such as changing or adding a layer of light gre ...

How can we modify this function to interpret multiple selections at once?

For the task of displaying multiple selections from a scrolling list to an alert, I have implemented the following function: var toppings = ""; function displaySelectedToppings() { var topList = document.getElementById('to ...

Create a single declaration in which you can assign values to multiple const variables

As a newcomer to react/JS, I have a question that may seem basic: I need multiple variables that are determined by a system variable. These variables should remain constant for each instance. Currently, my approach is functional but it feels incorrect to ...

What is the best approach to accumulate model data in an Angular JS service or controller through a series of consecutive calls?

I am facing a challenge where I need to display the results of multiple REST server calls on a single page using AngularJS. The initial call retrieves details about a specific product, including the IDs of other related products. My goal is to not only s ...

When the email field is changed, the string is not being set to the state if it is

I encountered a strange issue while setting an email input as a string to state. Even though I can see on React Dev Tools that it gets sent, when I try to log it from another function, I get an empty string. The odd part is, if I change the order of the in ...

The contenteditable div's selectAll feature doesn't function properly when it gains focus

I'm working with divs in a table structure and here's an example: <div contenteditable="true" onfocus="document.execCommand('selectAll',false,null)">Something</div> Clicking on a div to focus works perfectly, selectin ...

Learn how to insert JavaScript code into the head of an iframe using jQuery

My goal is to inject javascript code into the head of an iframe using jquery with the code provided below. var snippets_js='<?php echo $snippets_javascript;?>'; var scriptjs = document.createElement("script"); scriptjs.type = "text/j ...

What is the reason that elements with % properties totaling 100% do not align next to each other?

I've been attempting to arrange two blocks side by side within another block, but they just don't seem to fit together smoothly. What could be causing this issue? .container {height: 200px; width: 400px; background:darkgrey;} .left {height: 100% ...

Sorting Columns in JQuery Datatables

Encountering an issue with JQuery DataTables (datatables.net) where it takes 2 clicks to sort the columns when there are only 2 rows in the table. The first column sorts on the first click, but subsequent columns require multiple clicks. Despite testing th ...

Error: Running the command 'yarn eg:'live-server'' is not a valid internal or external command

Currently, I am utilizing yarn v1.6.0 to manage dependencies. I have globally installed live-server by running the following command: yarn global-add live-server However, upon executing it as live server, I encounter the following error: 'live-ser ...

Filtering rows in JQgrid is made easy after the addition of a new record

Here's the situation I'm facing: Every second, my script adds a new record using the "setInterval" function: $("#grid").jqGrid('addRowData', id, data, 'first').trigger("reloadGrid"); However, when users apply filters while t ...

Is it possible to run my NPM CLI package on CMD without needing to install it globally beforehand?

I've created a new NPM package, complete with its own set of CLI commands. Let's call this package xyz, and let's imagine it's now live on npmjs.com Now, picture a user who installs this package in their project by executing npm insta ...

Incorporating a specific time to a JavaScript date object

In my Angular application, I am facing an issue with adding a time to a date. The appointmentDate from the date picker returns a JavaScript date while the appointmentTime is selected from a dropdown with options like "8:00", "8:30", "9:00", etc. I'm ...

Executing getJSON requests in perfect synchronization of time

For my weather project, I have two JSON requests to make. The data from the first request is needed in order to personalize the second request for the user. The first request retrieves the latitude and longitude of the user, which are then required for the ...

Limiting the Maximum Height of 'material-react-table'

I'm struggling with a seemingly simple issue that I can't seem to solve. I'm working with material-react-table and having trouble getting the tables to properly adjust to their container. For instance, when setting a max height of 300px for ...

I encountered a problem with my code where the effect callbacks are synchronous to avoid race conditions. I am currently struggling to format it in the desired manner

Despite following the same format as examples, I keep receiving this error message. const response = await axios.get('http://localhost:5000/get-tasks') const dataObject = response.data const arrayOfKeys = Object.keys(dataObject ...

Enhanced User Experience Through Triggered Content Recommendations based on Scrolling Patterns

When a user scrolls beyond a certain point on a webpage, I would like a recommended content popup to slide out from the right side at the bottom of the page. An excellent example can be seen on USAToday where a blue recommended box appears as you scroll d ...

Issue with jQuery fadeTo() not working after appendTo() function completes

I am facing a problem with the code below that is meant to create a carousel effect for my website. The main issue I am encountering is that the original fadeTo() function does not actually fade the elements, but rather waits for the fade time to finish an ...

The PHP random number generator appears to be malfunctioning when being compared to the $_POST[] variable

In this section, random numbers are generated and converted to strings. These string values are then used in the HTML. $num1 = mt_rand(1, 9); $num2 = mt_rand(1, 9); $sum = $num1 + $num2; $str1 = (string) $num1; $str2 = (string) $num2; The following code ...

Having trouble retrieving data from redux toolkit using typescript

I've been diving into the world of Typescript by building a simple todo app using React, Redux-toolkit, and Typescript. One issue I encountered is when trying to access data from the store with useSelector. The retrieved object contains the desired va ...