React + MobX + Electron + Node.js + MongoDB 全棧項目開發實踐(一)

豐富功能

繼續參照上一篇中介紹的知乎文章,借鑑一些想法,又加入本身的一些想法,開始初步完成一個應用的閉環。css

任務拆分

一開始只是實現了很是簡單的加分減分功能,這樣雖然方便本身給本身記分,可是限制太少,也沒有具體的目標。所以,爲了作出相對完整的功能,開始細化任務及其數據結構。react

設想了一下每日任務打卡的場景,畫了一些流程草圖,逐步定下來了任務的相關數據:數據庫

任務 id (暫時先用任務標題)
用戶 id (目前是單用戶,默認爲 0)
標題(任務名稱)
描述
類型(是任務仍是慾望)
分數(根據類型決定加分仍是減分)
天天最多使用次數
建立時間
最近更新

複製代碼

目前,任務以 JSON 格式存儲在一個 JS 文件中。以後會將其存入數據庫中。數組

任務的相關功能:緩存

  • 添加任務
  • 查詢任務
  • 修改任務
  • 刪除任務
  • 打卡

無非就是數據庫的 CURD 工做。bash

組件/頁面設計

數據(或者 state)要由組件來承載。如今構思到的組件是:分數顯示組件、任務組件以及導航組件。antd

導航組件貫穿整個 APP,首頁顯示分數組件,經過導航進入任務/慾望界面,並在該界面顯示相應的任務/慾望。數據結構

在第 0 篇中,由於剛寫出來的乞丐乞丐版是真·SPA,因此只須要用 local state,加上 localStorage 來緩存數據以便以後讀取。post

代碼長這樣:學習

import React, { Component } from 'react';
import './App.css';
import { Row, Button, Icon } from 'antd';

class App extends Component {
  constructor(props){
    super(props);
    this.state = {
      score: localStorage.getItem('score') ? parseInt(localStorage.getItem('score')) : 0
    };
    this.increase = this.increase.bind(this);
    this.decrease = this.decrease.bind(this);
    this.clearScore = this.clearScore.bind(this);

  }

  increase(){
    this.setState({
      score: this.state.score + 1
    });
  }

  decrease(){
    this.setState({
      score: this.state.score - 1
    });
    console.log(this.state.score);
  }

  clearScore(){
    this.setState({
      score: 0
    });
  }

  componentDidUpdate() {
    localStorage.setItem('score', this.state.score);
  }

  render() {
    return (
      <div className="App">
        <Row>
          <Button className="operation" onClick={this.increase}>
            <Icon type="plus" />
          </Button>
        </Row>
        <Row>
          <Button className="operation" onClick={this.decrease}>
            <Icon type="minus" />
          </Button>
        </Row>
        <div className="score">
          <h2>{this.state.score}</h2>
        </div>
        <div className="clear">
          <Button onClick={this.clearScore}>Clear</Button>
        </div>
      </div>
    );
  }
}

export default App;

複製代碼

local storage 有個小坑,就是存進去的數值被轉化成字符串了。所以每次讀取的時候都須要轉回數字。

有了頁面、組件之後,更新分數的方法被綁在了 task 組件上,這樣不能更新到上一級頁面的分數。因此每次點擊完都須要刷新頁面,讓任務頁面組件讀取本地緩存。

// ListPage 做爲全部項目的容器
import React, { Component } from 'react';
import { Row, Col, Button } from 'antd';
import "./ListPage.css";

class ListPage extends Component {
  constructor(props) {
    super(props);
    this.state = {
      score: localStorage.getItem('score') ? parseInt(localStorage.getItem('score')) : 0
    };
  }

  clearScore() {
    this.setState({
      score: 0
    });
  }

  componentDidUpdate() {
    localStorage.setItem('score', this.state.score);
  }

  render() {
    const { type } = this.props.match.params;
    console.log(type);
    return (
      <div> <Row> <div className="score-list"> <h2>{this.state.score}</h2> </div> </Row> </div>
    );
  }
}

export default ListPage;

複製代碼
// 容器中讀取 list 數據,每個數據對應一個 ListItem
import React, { Component } from 'react';
import { Card, Row, Col, Button } from 'antd';

import "./ListItem.css";

class ListItem extends Component {
  constructor(props){
    super(props)
    this.state = {
      buttonVisible: false
    }
  }
  onClickListItem(itemInfo) {
    console.log(itemInfo.name, itemInfo.type)
    this.setState({
      buttonVisible: !this.state.buttonVisible
    })
  }
  changeScore(itemInfo) {
    let score = parseInt(localStorage.getItem("score"))
    if(itemInfo.type === "task") {
      score += itemInfo.score
    } else {
      score -= itemInfo.score
    }
    localStorage.setItem("score", score)
  }
  render(){
    const { itemInfo } = this.props
    return (
      <Card className="list-item" onClick={() => {this.onClickListItem(itemInfo)}}> <Row> <Col span={16} className="list-item-info"> <h3>{itemInfo.name}</h3> <p>{itemInfo.desc}</p> </Col> <Col span={8}> {itemInfo.type==="task" && <div className="item-score">+{itemInfo.score}</div>} {itemInfo.type==="desire" && <div className="item-score-desire">-{itemInfo.score}</div>} </Col> </Row> {this.state.buttonVisible && (<Row> <Button onClick={() => {this.changeScore(itemInfo)}}>打卡</Button> </Row>)} </Card>
    )
  }
}

export default ListItem;
複製代碼

這時就須要一個全局的狀態管理。 (是否有更簡單暴力的方法呢?好比自動刷新頁面?或許能夠,可是這會影響使用體驗,且不利於之後增長其餘功能,遲早會形成混亂。)

曾經使用過 Redux,剛入門的時候感受到很是痛苦。又要 action,action types,reducer,store。雖然最後大體搞明白了,可是仍是留下了一些坑,還有一個更新數據會賦值爲對象的一個奇怪 bug。因此,接下來的文章中,我會邊學習 MobX 邊總結 Redux 的思想,將二者進行對比。

系列文章

React + MobX + Electron + Node.js + MongoDB 全棧項目開發實踐(零)

相關文章
相關標籤/搜索