Lucifier129 / react-lite

An implementation of React v15.x that optimizes for small script size
MIT License
1.73k stars 98 forks source link

Some events are triggered twice in Firefox #99

Closed tszekely-spotcap closed 7 years ago

tszekely-spotcap commented 7 years ago

Some events, if not all, are triggered twice in FF. Examples: "onchange", "ondrop".

Lucifier129 commented 7 years ago

Sorry, I can't repreduce this problem, onDrag event is always triggered once in Chrome, Firefox and IE11.

The code is like below.

// use create-react-app
import React, { Component } from 'react-lite'
import ReactDOM from 'react-lite'

class App extends Component {
    state = {
        isDrop: false,
        value: '',
    }
    handleChange = event => {
        console.log('handleChange', event.currentTarget.value)
        this.setState({
            value: event.currentTarget.value,
        })
    }
    handleDragOver = event => {
        event.preventDefault()
    }
    handleDrop = event => {
        console.log('handleDrop')
        event.preventDefault()
        this.setState({
            isDrop: true
        })
    }
    render() {
        let blueElem = (
            <img
                draggable="true"
                src="http://www.w3school.com.cn/i/eg_dragdrop_w3school.gif"
            />
        )

        return (
            <div>
                <p>drag and drop the image in to box</p>
                <div
                    onDrop={this.handleDrop}
                    onDragOver={this.handleDragOver}
                    style={{
                        width:198,
                        height:100,
                        padding:10,
                        border: '1px solid #aaaaaa',
                    }}
                >
                    { this.state.isDrop && blueElem }
                </div>
                <br />
                { !this.state.isDrop && blueElem }
                <div><input onChange={this.handleChange} value={this.state.value} /></div>
            </div>
        )
    }
}

ReactDOM.render(<App />, document.getElementById('root'))
tszekely-spotcap commented 7 years ago

Hi @Lucifier129 ,

I should have been more descriptive. The problem happens in minified/production code. I've narrowed it down to react-lite since it doesn't happen with regular React.

My code is like:

import Checkbox from 'react-mdl/lib/Checkbox';
...
intervals.map(interval => (
            <Checkbox
              key={interval.title}
              name={interval.title}
              label={interval.title}
              checked={interval.checked}
              disabled={interval.disabled}
              className={interval.partial ? 'is-indeterminate' : ''}
              onChange={e => this.handleChangeIntervalCheckbox(interval, e)} />
          ))

and

import Dropzone from 'react-dropzone';
...
<Dropzone
        className="display-block dropzone"
        activeClassName="dropzone--active"
        rejectClassName="dropzone--reject"
        maxSize={CONFIG.MAX_FILE_SIZE}
        disableClick
        onDropAccepted={this.handleDropAccepted}
        onDropRejected={this.handleDropRejected}
        ref={(n) => { this.dropzone = n; }}>
      ...
      </Dropzone>

Please try with minified code, and a checkbox for the input with change listener. If you still can't reproduce it, I'll try to narrow it down even more when I have some time. Thanks for looking into it.

Lucifier129 commented 7 years ago

It can't be reproduced too, the code is like below

// use create-react-app, and config webpack-alias from react to react-lite
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Checkbox from 'react-mdl/lib/Checkbox';
import 'react-mdl/extra/material.css'
import 'react-mdl/extra/material.js'

class App extends Component {
    state = {
        checked: false,
    }
    handleChange = ({ currentTarget }) => {
        this.setState({
            checked: !this.state.checked
        })
        console.log('change')
    }
    render() {
        return (
            <div>
                <Checkbox
                  name="test"
                  label="label"
                  checked={this.state.checked}
                  onChange={this.handleChange} />
            </div>
        )
    }
}

ReactDOM.render(<App />, document.getElementById('root'))
olehreznichenko commented 7 years ago

Yes, in prod build have twice onChange event in select

aliebling commented 7 years ago

We're seeing the same behaviour for select.onchange. The onchange eventhandler ends up getting triggered twice, once with an oninput event and then with an onchange event. I'm assuming this has to do with the commit:

https://github.com/Lucifier129/react-lite/commit/2079e88e3277f2a6ce321715b59224f0ad18ef51

where the addEvent method has:

if (eventType === 'onchange') { addEvent(elem, 'oninput', listener); }

I'm not sure what the goal of the commit was, but it seems fundamentally broken for selects.

Lucifier129 commented 7 years ago

I got it,I will try to fix it soon;)