React不会在重新渲染时更新样式

时间:2017-07-20 14:07:57

标签: javascript css reactjs drag-and-drop

我有一个React组件,用户可以更改其可见性和位置。

通过添加和删除CSS类的可见性,通过函数的位置,设置Drag&之后的新位置。落在顶部和左侧。

这样可行,但我的问题是当组件被重新渲染为可见性时,React不会更新样式(因此不会将位置重写为初始值)。

manifest.xml

首次呈现卡片时,样式看起来像<application android:name="android.support.multidex.MultiDexApplication" //this line > </application>

当卡片移动时,样式看起来像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;",无论我如何创建样式对象。

那么,我如何强制React更新样式呢? 或者还有另一种方法可以实现这一目标吗?

2 个答案:

答案 0 :(得分:0)

答案的简短版本:

使用内部状态和组件生命周期

长版:

首先,我建议将事件处理程序放在组件中而不是全局方法中:

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

为了让组件更新&#39;或重新渲染,我建议在这种情况下改变其内部状态。因此,您首先在componentWillMount中的初始状态中添加初始值。

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

在事件处理程序中,您现在可以使用this.setState更新innerState的top和left(以及您需要绑定它的内容)。

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

答案 1 :(得分:0)

好的,得到了​​一个基于Andrew,dejakob和Chris答案的解决方案,谢谢大家:)

我最初想过,我无法将函数移动到Component中,因为具有最终位置的Drop事件是由元素发出的,我放弃了我的卡,而不是卡本身。

但是有一个dragend事件,由卡发出并包含位置。

现在我只需要使用它来设置状态中的位置(并通过父级中的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>
    }
}