Webアプリの勉強に家計簿を作ってみる

モチベーション

社会人になって出費が増えたのでちゃんと管理しようと思って
データベースの勉強も兼ねて家計簿アプリを製作します.
あとはMarkdownの練習. f:id:Libra23:20200109061153p:plain

開発環境

開発環境は下記の通り.

PC : Mac OS 10.14
Node : 12.12.0
npm : 6.13.1
Framework : React & Express
Mysql : 8.0.18

構成

f:id:Libra23:20200109061754j:plain

フロントエンドはReactでバックエンドはExpressで開発しています.
サーバーを分ける必要はないと思うんだけど,
複数人数で開発すること考えるとこうした方が勉強になると思って

この図を見るとExpressを介さずにデータベースにアクセスしたした方がよくね,と思っちゃう(体系的に勉強したい,,,)

フロント側

UIについて
React Bootstrapのコンポーネントを利用しています.
Material UIも使ってみよう. f:id:Libra23:20200109220546j:plain AddとかEditボタンを押したら表示されるモーダル f:id:Libra23:20200109220600j:plain

UIソースコード

<div>
    <Navbar bg="dark" variant="dark">
        <Navbar.Brand>
            Receipt App
        </Navbar.Brand>
        <ButtonGroup>
            <Button size="sm" variant="light" onClick={onClickBack}>&lt;</Button>
            <Button size="sm" variant="light" onClick={onClickNext}>&gt;</Button>
        </ButtonGroup>
        <Navbar.Text>
            {year}/{month}
        </Navbar.Text>
        <Navbar.Collapse className="justify-content-end">
        <ButtonGroup>
            <Button variant="primary" onClick={onClickAdd}>Add</Button>
            <Button variant="secondary" onClick={onClickRefresh}>Refresh</Button>
        </ButtonGroup>
        </Navbar.Collapse>
    </Navbar>

    <Modal show={show} onHide={onHide}>
        <Modal.Header closeButton>
            <Modal.Title>Edit Menu</Modal.Title>
        </Modal.Header>
        <Modal.Body>
            <Edit element={focusReceipt} onSubmit={onClickSave} onClick={onClickDelete}/>
        </Modal.Body>
    </Modal>
    <ReceiptTable
    onClick={onClickEdit}
    header={receiptHeader} 
    list={receiptList.filter((e) => {return e.Month==month})}/>
</div>

REST APIの一例

const onRead = (e) => {
    console.log('Call read');
    fetch('http://localhost:3000/api/receipts', {
        method: 'GET',
        headers : { "Content-type" : "application/json; charset=utf-8" },
        body: JSON.stringify(requsetBody)
    })
    .then(response => response.json())
    .then(json => {
        console.log(json);
        setReceiptList(json);
    })
    .catch(error => console.error('Error:', error))
}

昔のReactだと ステートの初期化はコンストラクターの中で

this.state={param:0}

ステートの変更は

this.setState({param: 10});

だったけど,最近のステートの初期化は

[param, function] = React.useState(0);

ステートの変更は

function(10);

となっている.

エンド側

コンソールでMysqlを編集するのが苦手なので,
サーバー起動時にデータベースを構築するようにした.

app.listen(3000, () => {
    console.log('Wake up', 'http://localhost:3000')
    connection.connect((err, result) => {
        if (err) {
            console.log('Fail Connecting database!');
            throw err;
        }
        console.log('Connected to database!');
        console.log(result);
    });
    connection.query('CREATE DATABASE IF NOT EXISTS ??', [DB_NAME], function (err, result) {
        if (err) {
            throw err;
        }
        console.log('Create');
        console.log(result);
    });
    connection.query('USE ??', [DB_NAME], function (err, result) {
        if (err) {
            throw err;
        }
        console.log('Use');
        console.log(result);
    });
    connection.query('CREATE TABLE IF NOT EXISTS ??(\
        id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, \
        Date DATE NOT NULL, \
        Year INT UNSIGNED, \
        Month INT UNSIGNED, \
        Day INT UNSIGNED, \
        Content VARCHAR(255) NOT NULL, \
        Amount INT UNSIGNED NOT NULL DEFAULT 0, \
        Shop VARCHAR(255), \
        Category INT UNSIGNED NOT NULL DEFAULT 0, \
        Necessity VARCHAR(255), \
        Note VARCHAR(255), \
        Flow VARCHAR(255) NOT NULL)', [MAIN_TABLE_NAME], function (err, result) {
        if (err) {
            throw err;
        }
        console.log('Create table');
        console.log(result);
    });
})

CRUD API(?)の一例

app.get('/api/receipts', (req, res) => {
    console.log('Call get & read');
    connection.query('SELECT * FROM ?? WHERE Month = ?', [MAIN_TABLE_NAME, req.body['Month']], function(err, results) {
        if (err) {
            throw err;
        }
        console.log(results);
        res.send(results);
    });
});

webpackを使って複数サーバー間で通信が必要になるので
フロントからのアクセス権をいじっておく

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "*");
    res.header("Access-Control-Allow-Methods", "*");
    next();
});

github.com

ポートフォリオ用に急いで書いたのと久々に書いたので
ブログとしては最悪な感じだなぁ
定期的に書く余裕をもつこととユーザー目線に立つことと心がけよう,,,