• React 组件:计时器例子



    learn from 《React全家桶:前端开发与实例详解》
    https://zh-hans.reactjs.org/tutorial/tutorial.html
    https://zh-hans.reactjs.org/docs/create-a-new-react-app.html#create-react-app

    本章学习的目标是做一个定时器

    1. 将应用程序分解为组件

    在这里插入图片描述
    在这里插入图片描述

    2. 构建应用静态版本

    app.js

    class TimersDashBoard extends React.Component {
        render() {
            return (
                <div className='ui three column centered grid'>
                    <div className='column'>
                        <EditableTimerList/>
                        <ToggleableTimerForm isOpen={true}/>
                    </div>
                </div>
            )
        }
    }
    
    class EditableTimerList extends React.Component {
        render() {
            return (
                <div id='timers'>
                    <EditableTimer
                        title='学习react'
                        project='react web'
                        elasped='3600'
                        runningSince={null}
                        editFormOpen={false}
                    />
                    <EditableTimer
                        title='学习python'
                        project='deep learning'
                        elasped='3600'
                        runningSince={null}
                        editFormOpen={true}
                    />
                </div>
            )
        }
    }
    
    class EditableTimer extends React.Component {
        render() {
            if (this.props.editFormOpen) {
                return (
                    <TimerForm
                        title={this.props.title}
                        project={this.props.project}
                    />
                )
            } else {
                return (
                    <Timer
                        title={this.props.title}
                        project={this.props.project}
                        elasped={this.props.elasped}
                        runningSince={this.props.runningSince}
                    />
                )
            }
        }
    }
    
    class TimerForm extends React.Component {
        render() {
            const submitText = this.props.title ? 'Update' : 'Create'
            return (
                <div className='ui centered card'>
                    <div className='content'>
                        <div className='ui form'>
                            <div className='field'>
                                <label>Title</label>
                                <input type='text' defaultValue={this.props.title}/>
                            </div>
                            <div className='field'>
                                <label>Project</label>
                                <input type='text' defaultValue={this.props.project}/>
                            </div>
                            <div className='ui two bottom attached buttons'>
                                <button className='ui basic blue button'>
                                    {submitText}
                                </button>
                                <button className='ui basic red button'>
                                    Cancel
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
    
    class ToggleableTimerForm extends React.Component {
        render() {
            if (this.props.isOpen) {
                return (
                    <TimerForm/>
                )
            } else {
                return (
                    <div className='ui basic content center aligned segment'>
                        <button className='ui basic button icon'>
                            <i className='plus icon'/>
                        </button>
                    </div>
                )
            }
        }
    }
    
    class Timer extends React.Component {
        render() {
            const elaspedString = helpers.renderElapsedString(this.props.elasped)
            return (
                <div className='ui centered card'>
                    <div className='content'>
                        <div className='header'>
                            {this.props.title}
                        </div>
                        <div className='meta'>
                            {this.props.project}
                        </div>
                        <div className='center aligned description'>
                            <h2> {elaspedString} </h2>
                        </div>
                        <div className='extra content'>
                            <span className='right floated edit icon'>
                                <i className='edit icon'/>
                            </span>
                            <span className='right floated trash icon'>
                                <i className='trash icon'/>
                            </span>
                        </div>
                    </div>
                    <div className='ui bottom attached blue basic button'>
                        Start
                    </div>
                </div>
            )
        }
    }
    
    ReactDOM.render(
        <TimersDashBoard/>,
        document.getElementById('content')
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142

    在这里插入图片描述
    改成 falseToggleableTimerFormrender 回返回 显示 plus icon 的分支
    在这里插入图片描述

    3. 哪些组件是有状态的

    • 是通过 props 从 父组件 传递进来的吗?是的话,它很可能不是 state
    • 不随时间变化,很可能不是 state
    • 可以根据其他 state 或 props 计算得到,不是 state

    原则就是用尽可能少的 state

    4. 每个 state 应该在哪个组件里

    如何确定,步骤:

    • 标识基于该state渲染的组件
    • 查找state共同所有者
    • 较高层次的组件拥有该state
    • 找不到的话,创建新组件来保存 state,并置于层次结构的上方

    5. 硬编码初始化state

    props 可理解为 : 不可改变的 state

    • TimersDashBoard
    class TimersDashBoard extends React.Component {
        state = {
            timers: [
                {
                    title: 'react learning',
                    project: 'web dev',
                    id: uuid.v4(),
                    elasped: 3600 * 1000,
                    runningSince: Date.now(),
                },
                {
                    title: 'python learning',
                    project: 'ai dev',
                    id: uuid.v4(),
                    elasped: 30 * 1000,
                    runningSince: null,
                }
            ]
        }
    
        render() {
            return (
                <div className='ui three column centered grid'>
                    <div className='column'>
                        <EditableTimerList
                            timers={this.state.timers}
                        />
                        <ToggleableTimerForm isOpen={false}/>
                    </div>
                </div>
            )
        }
    }
    
    class EditableTimerList extends React.Component {
        render() {
            const timers = this.props.timers.map(
                (timer) => (
                    <EditableTimer
                        key={timer.id}
                        id={timer.id}
                        title={timer.title}
                        project={timer.project}
                        elasped={timer.elasped}
                        runningSince={timer.runningSince}
                    />
                )
            )
            return (
                <div id='timers'>
                    {timers}
                </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 表单是有状态的
    class EditableTimer extends React.Component {
        state = {
            editFormOpen: false,
        }
        render() {
            if (this.state.editFormOpen) {
                return (
                    <TimerForm
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                    />
                )
            } else {
                return (
                    <Timer
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                        elasped={this.props.elasped}
                        runningSince={this.props.runningSince}
                    />
                )
            }
        }
    }
    
    class TimerForm extends React.Component {
        state = {
            title: this.props.title || '',
            project: this.props.project || '',
        }
        handleTitleChange = (e) => {
            this.setState({title: e.target.value})
        }
        handleProjectChange = (e) => {
            this.setState({project: e.target.value})
        }
        render() {
            const submitText = this.props.title ? 'Update' : 'Create'
            return (
                <div className='ui centered card'>
                    <div className='content'>
                        <div className='ui form'>
                            <div className='field'>
                                <label>Title</label>
                                <input type='text' value={this.state.title}
                                    onChange={this.handleTitleChange}/>
                            </div>
                            <div className='field'>
                                <label>Project</label>
                                <input type='text' value={this.state.project}
                                       onChange={this.handleProjectChange}/>
                            </div>
                            <div className='ui two bottom attached buttons'>
                                <button className='ui basic blue button'>
                                    {submitText}
                                </button>
                                <button className='ui basic red button'>
                                    Cancel
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
    
    class ToggleableTimerForm extends React.Component {
        state = {
            isOpen: false,
        }
        handleFormOpen = () => {
            this.setState({isOpen: true});
        }
        render() {
            if (this.state.isOpen) {
                return (
                    <TimerForm/>
                )
            } else {
                return (
                    <div className='ui basic content center aligned segment'>
                        <button
                            className='ui basic button icon'
                            onClick={this.handleFormOpen}>
                            <i className='plus icon'/>
                        </button>
                    </div>
                )
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    6. 添加反向数据流

    TimerForm组件

    • 表单创建、更新计时器
    • 取消动作

    让父组件拥有函数(在事件发生时决定采取什么行为),父组件 通过 props 将函数传递给 TimerForm

    class TimerForm extends React.Component {
        state = {
            title: this.props.title || '',
            project: this.props.project || '',
        }
        handleTitleChange = (e) => {
            this.setState({title: e.target.value})
        }
        handleProjectChange = (e) => {
            this.setState({project: e.target.value})
        }
        handleSubmit = () => {
            this.props.onFormSubmit({
                id: this.props.id,
                title: this.state.title,
                project: this.state.project,
            })
        }
        render() {
            const submitText = this.props.id ? 'Update' : 'Create'
            return (
                <div className='ui centered card'>
                    <div className='content'>
                        <div className='ui form'>
                            <div className='field'>
                                <label>Title</label>
                                <input type='text' value={this.state.title}
                                    onChange={this.handleTitleChange}/>
                            </div>
                            <div className='field'>
                                <label>Project</label>
                                <input type='text' value={this.state.project}
                                       onChange={this.handleProjectChange}/>
                            </div>
                            <div className='ui two bottom attached buttons'>
                                <button className='ui basic blue button'
                                        onClick={this.handleSubmit}>
                                    {submitText}
                                </button>
                                <button className='ui basic red button'
                                        onClick={this.props.onFormClose}>
                                    Cancel
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • ToggleableTimerForm 组件
    class ToggleableTimerForm extends React.Component {
        state = {
            isOpen: false,
        }
        handleFormOpen = () => {
            this.setState({isOpen: true});
        }
        handleFormClose = () => {
            this.setState({isOpen: false});
        }
        handleFormSubmit = (timer) => {
            this.props.onFormSubmit(timer);
            this.setState({
                isOpen: false,
            })
        }
        render() {
            if (this.state.isOpen) {
                return (
                    <TimerForm
                        onFormSubmit={this.handleFormSubmit}
                        onFormClose={this.handleFormClose}
                    />
                )
            } else {
                return (
                    <div className='ui basic content center aligned segment'>
                        <button
                            className='ui basic button icon'
                            onClick={this.handleFormOpen}>
                            <i className='plus icon'/>
                        </button>
                    </div>
                )
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • TimersDashBoard 组件
    	handleCreateFormSubmit = (timer) => {
            this.createTimer(timer);
        }
        createTimer = (timer) => {
            const t = helpers.newTimer(timer);
            this.setState({
                timers: this.state.timers.concat(t),
            })
        }
    	render() {
    	        return (
    	            <div className='ui three column centered grid'>
    	                <div className='column'>
    	                    <EditableTimerList
    	                        timers={this.state.timers}/>
    	                    <ToggleableTimerForm
    	                        onFormSubmit={this.handleCreateFormSubmit}/>
    	                </div>
    	            </div>
    	        )
    	    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述
    在这里插入图片描述
    还不能开始,删除,修改

    • 更新计时器
      编辑 Timer 组件,添加函数 onEditClick
    						<span
                                className='right floated edit icon'
                                onclick={this.props.onEditClick}>
                                <i className='edit icon'/>
                            </span>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • EditableTimer 组件
    	state = {
            editFormOpen: false,
        }
        handleEditClick = () => {
            this.openForm()
        }
        handleFormClose = () => {
            this.closeForm()
        }
        handleSubmit = (timer) => {
            this.props.onFormSubmit(timer);
            this.closeForm();
        }
        closeForm = () => {
            this.setState({editFormOpen: false});
        }
        openForm = () => {
            this.setState({editFormOpen: true});
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    这些函数作为 props 向下传递

    	render() {
            if (this.state.editFormOpen) {
                return (
                    <TimerForm
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                        onFormSubmit={this.handleFormSubmit}
                        onFormClose={this.handleFormClose}
                    />
                )
            } else {
                return (
                    <Timer
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                        elapsed={this.props.elapsed}
                        runningSince={this.props.runningSince}
                        onEditClick={this.handleEditClick}
                    />
                )
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • EditableTimerList 添加 onFormSubmit={this.props.onFormSubmit}
    class EditableTimerList extends React.Component {
        render() {
            const timers = this.props.timers.map(
                (timer) => (
                    <EditableTimer
                        key={timer.id}
                        id={timer.id}
                        title={timer.title}
                        project={timer.project}
                        elapsed={timer.elapsed}
                        runningSince={timer.runningSince}
                        onFormSubmit={this.props.onFormSubmit}
                    />
                )
            )
            return (
                <div id='timers'>
                    {timers}
                </div>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 顶层组件 TimersDashBoard
    	handleEditFormSubmit = (attrs) => {
            this.updateTimer(attrs);
        }
        updateTimer = (attrs) => {
            this.setState({
                timers: this.state.timers.map((timer) => {
                    if (timer.id === attrs.id) {
                        return Object.assign({}, timer,{
                            title: attrs.title,
                            project: attrs.project,
                        })
                    }
                    else{
                        return timer;
                    }
                })
            })
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    属性传递给 EditableTimerList

    					<EditableTimerList
                            timers={this.state.timers}
                            onFormSubmit={this.handleEditFormSubmit}
                        />
    
    • 1
    • 2
    • 3
    • 4

    删除计时器

    Timer

    	handleTrashClick = () => {
            this.props.onTrashClick(this.props.id)
        }
    	。。。
    						<span className='right floated trash icon'
                                onClick={this.this.handleTrashClick}>
                                <i className='trash icon'/>
                            </span>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    向上传递 EditableTimer

    		else {
                return (
                    <Timer
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                        elapsed={this.props.elapsed}
                        runningSince={this.props.runningSince}
                        onEditClick={this.handleEditClick}
                        onTrashClick={this.props.onTrashClick} // add
                    />
                )
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    向上传递 EditableTimerList

    			<EditableTimer
                        key={timer.id}
                        id={timer.id}
                        title={timer.title}
                        project={timer.project}
                        elapsed={timer.elapsed}
                        runningSince={timer.runningSince}
                        onFormSubmit={this.props.onFormSubmit}
                        onTrashClick={this.props.onTrashClick}  // add
                    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    TimersDashBoard 顶层实现这个删除函数

    	handleTrashClick = (timerId) => {
            this.deleteTimer(timerId);
        }
        deleteTimer = (timerId) => {
            this.setState({
                timers: this.state.timers.filter(t => t.id !== timerId)
            })
        }
        。。。
    					<EditableTimerList
                            timers={this.state.timers}
                            onFormSubmit={this.handleEditFormSubmit}
                            onTrashClick={this.handleTrashClick} // add
                        />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述

    • 计时器还不能工作

    Timer组件

    	componentDidMount() {
            this.forceUpdateInterval = setInterval(() => this.forceUpdate(), 50)
        } // 每 50 ms 调用一次 forceUpdate,重新渲染
        componentWillUnmount() {
            clearInterval(this.forceUpdateInterval)
        }  // 停止 forceUpdateInterval 的间隔执行,计时器删除之前调用
    
        handleTrashClick = () => {
            this.props.onTrashClick(this.props.id)
        }
    
        render() {
            const elapsedString = helpers.renderElapsedString(this.props.elapsed, this.props.runningSince)
            return (
            。。。
            )
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    添加启动,停止

    	handleStartClick = () => {
            this.props.onStartClick(this.props.id)
        }
    
        handleStopClick = () => {
            this.props.onStopClick(this.props.id)
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在 Timer 的 return 最底部添加 新组件

    				<TimerActionButton
                        timerIsRunning={!!this.props.runningSince}
                        onStartClick={this.handleStartClick}
                        onStopClick={this.handleStopClick}
                    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • TimerActionButton
    class TimerActionButton extends React.Component {
        render() {
            if (this.props.timerIsRunning) {
                return (
                    <div
                        className='ui bottom attached red basic button'
                        onClick={this.props.onStopClick}
                    >
                        Stop
                    </div>
                )
            } else {
                return (
                    <div
                        className='ui bottom attached green basic button'
                        onClick={this.props.onStartClick}
                    >
                        Start
                    </div>
                )
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    这些事件需要在上层结构中传递

    EditableTimer

    				<Timer
                        id={this.props.id}
                        title={this.props.title}
                        project={this.props.project}
                        elapsed={this.props.elapsed}
                        runningSince={this.props.runningSince}
                        onEditClick={this.handleEditClick}
                        onTrashClick={this.props.onTrashClick}
                        onStartClick={this.props.onStartClick} // add
                        onStopClick={this.props.onStopClick} // add
                    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    EditableTimerList

    				<EditableTimer
                        key={timer.id}
                        id={timer.id}
                        title={timer.title}
                        project={timer.project}
                        elapsed={timer.elapsed}
                        runningSince={timer.runningSince}
                        onFormSubmit={this.props.onFormSubmit}
                        onTrashClick={this.props.onTrashClick}
                        onStartClick={this.props.onStartClick} // add
                        onStopClick={this.props.onStopClick} // add
                    />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    TimersDashBoard

    	handleStartClick = (timerId) => {
            this.startTimer(timerId);
        }
    
        startTimer = (timerId) => {
            const now = Date.now();
            this.setState({
                timers: this.state.timers.map((timer) => {
                    if(timer.id === timerId) {
                        return Object.assign({}, timer, {
                            runningSince: now
                        })
                    }else{
                        return timer;
                    }
                })
            })
        }
    
        handleStopClick = (timerId) => {
            this.stopTimer(timerId);
        }
    
        stopTimer = (timerId) => {
            const now = Date.now();
            this.setState({
                timers: this.state.timers.map((timer) => {
                    if(timer.id === timerId) {
                        const lastElapsed = now - timer.runningSince;
                        return Object.assign({}, timer,{
                            elapsed: timer.elapsed + lastElapsed,
                            runningSince: null
                        })
                    } else {
                        return timer;
                    }
                })
            })
        }
    
    。。。
    
    					<EditableTimerList
                            timers={this.state.timers}
                            onFormSubmit={this.handleEditFormSubmit}
                            onTrashClick={this.handleTrashClick}
                            onStartClick={this.handleStartClick} //add
                            onStopClick={this.handleStopClick}  //add
                        />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在这里插入图片描述

    7. 添加服务器通信

    上面的计时器状态不可以保存,需要保存在服务器上

    见下一章

  • 相关阅读:
    使用python来访问Hadoop HDFS存储实现文件的操作
    一分钟看懂“低代码“是什么?低代码真能“砸“掉程序员饭碗?
    ​iOS上架App Store的全攻略
    Redis从入门到放弃(11):雪崩、击穿、穿透
    嵌入式Linux裸机开发(一)基础介绍及汇编LED驱动
    ChatGPT全球最大开源平替OpenAssistant:基于Pythia和LLaMA微调而来
    Docker从零到实战
    用C++写一个生成n个m之内的随机整数的函数
    Java代码中验证在 try 之前的代码如果出异常了 finally 是否还会执行
    oracle 执行计划详解
  • 原文地址:https://blog.csdn.net/qq_21201267/article/details/125710386