簡體   English   中英

React 不會在重新渲染時更新樣式

[英]React does not update style on rerender

我有一個 React 組件,用戶可以更改其可見性和位置。

通過添加和刪除 CSS 類的可見性,通過函數的位置,將拖放后的新位置設置為頂部和左側。

這行得通,但我的問題是 React 不會更新樣式(因此不會將位置重寫為初始位置),當組件被重新渲染以獲得可見性時。

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)

第一次渲染卡片時,樣式看起來像style="top: initial; left: initial;" .

當卡片被移動時,樣式看起來像style="top: 162px; left: 320px;" .

當卡片關閉時,類hide被添加,但樣式保持style="top: 162px; left: 320px;" ,不管我如何創建樣式對象。

那么,我怎樣才能強制 React 更新樣式呢? 還是有另一種方法可以做到這一點?

答案的簡短版本:

使用內部狀態和組件生命周期

長版:

首先,我建議將您的事件處理程序放在組件中而不是全局方法中:

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

其次,在組件的構造函數中,將組件的 this-context 綁定到這些處理程序。 (好吧,或者你在渲染方法中使用箭頭函數)

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

為了讓組件“更新”或重新渲染,我建議在這種情況下改變其內部狀態。 因此,您首先在componentWillMount 內的初始狀態中添加一個初始值。

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

在事件處理程序中,您現在可以使用 this.setState 更新 innerState 的 top 和 left(這就是您綁定 this 所需要的)。

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

通過使用 setState,將使用內部狀態的新值觸發重新渲染。 現在,您可以在您的渲染方法中使用this.state.topthis.state.left

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

好的,根據 Andrew、dejakob 和 Chris 的回答得到了解決方案,謝謝大家 :)

我最初認為,我無法將函數移動到組件中,因為具有最終位置的放置事件是由我放置卡片的元素發出的,而不是卡片本身。

但是有一個dragend事件,它由 Card 發出並包含位置。

現在我只需要使用它來設置狀態中的位置(並通過 ref 將其刪除到父級中的unsetPosition )。

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>
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM