Reactjs setState不仅仅为这一个函数更新

时间:2017-08-04 16:30:58

标签: reactjs

对于此应用程序,单击列出的项目一次应在此列出的项目下创建一个按钮组件。单击该按钮应该会删除此列出的项目。

我目前在尝试删除'单击按钮后列出的项目。这是出错的代码(可在CountdownApp组件中找到):

handleDelete(index) {
    console.log('in handleDelete')
    console.log(index)
    let countdownList = this.state.countdowns.slice()
    countdownList.splice(index, 1)
    console.log(countdownList) // countdownList array is correct

    this.setState({
        countdowns: countdownList
    }, function() {
        console.log('after setState')
        console.log(this.state.countdowns) // this.state.countdowns does not match countdownList
        console.log(countdownList) // countdownList array is still correct
    })
}

在上面的代码中,我使用splice从countdownList数组中删除了要删除的项目,并尝试使用setState重新呈现应用程序。但是,新的州倒计时并未反映出这种变化。实际上,它返回未经编辑的状态。

我也尝试了以下内容:

handleDelete(index) {
    this.setState({
        countdowns: [] // just using an empty array to check if setState still works
    }, function() {
        console.log('after setState')
        console.log(this.state.countdowns)
    })
}

在上面的代码中,我尝试将state设置为空数组。 this.state.countdowns的控制台日志没有打印出一个空数组。它再次打印出未经编辑的状态

这是唯一没有工作的事件处理程序,我不知道为什么(这篇文章的主要问题):/

如果我有' setstate'错误地,为什么另一个' setState'在我的代码的其他部分工作? (我想请求深入解释)

这是我在这个应用程序(它的一个小应用程序)的所有代码:

import React from 'react'
import ReactDOM from 'react-dom'

class DeleteButton extends React.Component {
    render() {
        return (
            <ul>
                <button onClick={this.props.onDelete}>
                    delete
                </button>
            </ul>
        )
    }
}

class Countdown extends React.Component {
    render () {
        //console.log(this.props)
        return (
            <li 
                onClick={this.props.onClick}
                onDoubleClick={this.props.onDoubleClick}
            >
                {this.props.title} - {this.props.days}, {this.props.color}
                {this.props.showDeleteButton ? <DeleteButton onDelete={this.props.onDelete}/> : null }
            </li>
        )
    }
}

const calculateOffset = date => {
    let countdown = new Date(date)
    let today = new Date
    let timeDiff = countdown.getTime() - today.getTime()
    let diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24))
    return diffDays
}

class CountdownList extends React.Component {
    countdowns() {
        let props = this.props
        // let onClick = this.props.onClick
        // let onDoubleClick = this.props.onDoubleClick
        let rows = []
        this.props.countdowns.forEach(function(countdown, index) {
             rows.push(
                <Countdown 
                    key={index}
                    title={countdown.title} 
                    days={calculateOffset(countdown.date)}
                    color={countdown.color}
                    showDeleteButton={countdown.showDeleteButton}
                    onDelete={() => props.onDelete(index)}
                    onClick={() => props.onClick(index)}
                    onDoubleClick={() => props.onDoubleClick(index)}
                />
            )           
        })
        return rows
    }

    render() {
        return (
            <div>
                <ul>
                    {this.countdowns()}
                </ul>
            </div>
        )
    }
}

class InputField extends React.Component {
    render() {
        return (
            <input 
                type='text'
                placeholder={this.props.placeholder}
                value={this.props.input}
                onChange={this.props.handleInput}
            />
        )
    }
}

class DatePicker extends React.Component {
    render() {
        return (
            <input 
                type='date'
                value={this.props.date}
                onChange={this.props.handleDateInput}
            />
        )
    }
}

class CountdownForm extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            title: this.props.title || '',
            date: this.props.date || '',
            color: this.props.color || ''
        }
    }

    componentWillReceiveProps(nextProps) {
        this.setState({
            title: nextProps.title || '',
            date: nextProps.date || '',
            color: nextProps.color || ''
        })
    }

    handleSubmit(e) {
        e.preventDefault()
        this.props.onSubmit(this.state, this.reset())
    }

    reset() {
        this.setState({
            title: '',
            date: '',
            color: ''
        })
    }

    handleTitleInput(e) {
        this.setState({
            title: e.target.value
        })
    }

    handleDateInput(e) {
        this.setState({
            date: e.target.value
        })
    }

    handleColorInput(e) {
        this.setState({
            color: e.target.value
        })
    }

    render() {
        return (
            <form
                onSubmit={(e) => this.handleSubmit(e)}
            >
                <h3>Countdown </h3>
                <InputField 
                    placeholder='title'
                    input={this.state.title}
                    handleInput={(e) => this.handleTitleInput(e)}
                />
                <DatePicker 
                    date={this.state.date}
                    handleDateInput={(e) => this.handleDateInput(e)}
                />
                <InputField 
                    placeholder='color'
                    input={this.state.color}
                    handleInput={(e) => this.handleColorInput(e)}
                />
                <button type='submit'>Submit</button>
            </form>
        )
    }
}

class CountdownApp extends React.Component {
    constructor() {
        super()
        this.state = {
            countdowns: [
                {title: 'My Birthday', date: '2017-07-25', color: '#cddc39', showDeleteButton: false},
                {title: 'Driving Practice', date: '2017-07-29', color: '#8bc34a', showDeleteButton: false},
                {title: 'Korean BBQ', date: '2017-08-15', color: '#8bc34a', showDeleteButton: false}
            ]
        }
    }

    handleCountdownForm(data) {
        if (this.state.editId) {
            const index = this.state.editId
            let countdowns = this.state.countdowns.slice()
            countdowns[index] = data
            this.setState({
                title: '',
                date: '',
                color: '',
                editId: null,
                countdowns
            })

        } else {
            data.showDeleteButton = false
            const history = this.state.countdowns.slice()
            this.setState({
                countdowns: history.concat(data),
            })
        }
    }

    handleDelete(index) {
        console.log('in handleDelete')
        console.log(index)
        let countdownList = this.state.countdowns.slice()
        countdownList.splice(index, 1)
        console.log(countdownList)

        this.setState({
            countdowns: countdownList
        }, function() {
            console.log('after setState')
            console.log(this.state.countdowns)
        })
    }

    handleCountdown(index) {
        const countdownList = this.state.countdowns.slice()
        let countdown = countdownList[index]
        countdown.showDeleteButton = !countdown.showDeleteButton
        this.setState({
            countdowns: countdownList
        })
    }

    handleDblClick(index) {
        const countdownList = this.state.countdowns
        const countdown = countdownList[index]
        this.setState({
            title: countdown.title,
            date: countdown.date,
            color: countdown.color,
            editId: index
        })
    }
render() {
    return (
        <div>
            <CountdownForm 
                title={this.state.title}
                date={this.state.date}
                color={this.state.color}
                onSubmit={(data) => {this.handleCountdownForm(data)}}
            />
            <CountdownList 
                countdowns={this.state.countdowns}
                onDelete={(index) => this.handleDelete(index)}
                onClick={(index) => this.handleCountdown(index)}
                onDoubleClick={(index) => this.handleDblClick(index)}
            />
        </div>
    )
}
}

ReactDOM.render(
    <CountdownApp />,
    document.getElementById('app')
)

1 个答案:

答案 0 :(得分:0)

我设法找到了自己问题的答案!

setState按预期工作。该错误是由于包含事件处理程序的<li>容器造成的。

单击<li>会导致它调用onClick事件(由CountdownApp组件中的handleCountdown函数管理),这会导致它成为setState。

由于删除按钮包含在<li>容器中,单击删除按钮会调用2个事件侦听器 - handleCountdown和handleDelete。在这种情况下,handleCountdown被调用两次,一次点击 class Countdown extends React.Component { render () { return ( <li> <div onClick={this.props.onClick} > // Add this div wrapper! {this.props.title} - {this.props.days}, {this.props.color} </div> {this.props.toShow ? <ButtonsGroup onDelete={this.props.onDelete} onEdit={this.props.onEdit} /> : null} </li> ) } } 进行展开,单击删除按钮时调用下一次调用。

从handleCountdown调度的最后一个异步setState很可能会覆盖handleDelete的setState。因此,错误。

以下是更改:(我重新编码所有内容,因此名称可能略有不同,但逻辑保持不变)

<li>

因此解决方案是将可点击区域和按钮分开。我在<li>中的文本上添加了一个div包装器,因此只要单击<ul>中的文本,添加的int SIZE = 1900; int[][] array = new int[SIZE][]; for (int i = 0; i < SIZE; i++) { array[i] = new int[1024 * 1024 / 4]; // 1MB Thread.sleep(10); if (i % 100 == 0 && i != 0) { System.out.println(i + "Mb added"); } } 就会超出onClick事件处理程序区域。