
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
服务器负责持久化数据,React app 数据持久化于 data.json 文件中

 书籍作者准备好了一个本地服务器 server.js (里面有一些 api 如 http://localhost:3000/api/timers 可以调用),data.json 数据
使用 api 测试软件,get http://localhost:3000/api/timers
[
	{
		"title": "Mow the lawn",
		"project": "House Chores",
		"elapsed": 5458797,
		"id": "0a4a79cb-b06d-4cb1-883d-549a1e3b66d7",
		"runningSince": null
	},
	{
		"title": "Clear paper jam",
		"project": "Office Chores",
		"elapsed": 1274709,
		"id": "a73c1d19-f32d-4aff-b470-cea4e792406a",
		"runningSince": null
	},
	{
		"title": "Ponder origins of universe",
		"project": "Life Chores",
		"id": "2c43306e-5b44-4ff8-8753-33c35adbd06f",
		"elapsed": 11750,
		"runningSince": 1456225941911
	}
]作者给我们提供了 client.js 现在我们要从服务器获取 Timers 的配置
错误写法: const timers = client.getTimers(),网络请求是 异步(防止 IO 阻塞) 的,被调用的函数本身不会返回有用的值
可以:传递一个函数进去,如果服务器成功返回结果,getTimers() 将在服务器返回消息后,调用传入的这个函数
client.getTimers((serverTimers) => ( // do something use serverTimers ))从服务器获取配置,每 5 秒刷新一下
class TimersDashBoard extends React.Component {
    state = {
        timers: []
    }
    componentDidMount() {
        this.loadTimersFromServer();
        setInterval(this.loadTimersFromServer, 5000);
    }
    loadTimersFromServer = () => {
        client.getTimers((serverTimers) => (
            this.setState({timers: serverTimers})
        ))
    }
    ...期间报错了:
SyntaxError: Unexpected token ] in JSON at position 602
    at JSON.parse (<anonymous>)
    at D:/gitcode/react/time_tracking_app/server.js:27:19报错是因为 json 文件格式问题 [{}, {}, {}, ] 最后一个 {} 后面不能跟 ,
不论你做什么,5 秒后肯定被服务器重置
如果你在客户端对服务器做了更新,他能同步到其他客户端(比如电商的库存数量)
	startTimer = (timerId) => {
        const now = Date.now();
        this.setState({
            timers: this.state.timers.map((t) => {
                if(t.id === timerId) {
                    return Object.assign({}, t, {
                        runningSince: now
                    })
                }
                else{
                    return t
                }
            })
        })
        client.startTimer({
            id: timerId,
            start: now
        })
    }
    stopTimer = (timerId) => {
        const now = Date.now();
        this.setState({
            timers: this.state.timers.map((t) => {
                if(t.id === timerId) {
                    const lastElapsed = now - t.runningSince;
                    return Object.assign({}, t, {
                        elapsed: lastElapsed + t.elapsed,
                        runningSince: null
                    })
                }
                else{
                    return t
                }
            })
        })
        client.stopTimer({
            id: timerId, stop: now
        })
    }	createTimer = (timer) => {
        const t = helpers.newTimer(timer);
        this.setState({
            timers: this.state.timers.concat(t)
        })
        client.createTimer(t)
    }	deleteTimer = (timerId) => {
        this.setState({
            timers: this.state.timers.filter(t => t.id !== timerId),
        })
        client.deleteTimer({id: timerId})
    }	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;
                }
            })
        })
        client.updateTimer(attrs)
    }现在所有的操作都会持久化到服务器,并且在不同的选项卡中同步
