React Mix 예제
설명
“Notice”의 예로 사용자 페이지를 페이지로 제외했습니다.
폴더 구조
react-mix1/
├── componets/
│ ├── NoticeAdminPage.js
│ ├── NoticeForm.js
│ └── NoticeList.js
├── service/
│ └── notice-admin-svc.js
├── app.js
└── admin.html
admin.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Notice Admin Page - React</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> -->
<!-- <script src="https://unpkg.com/logic-bind-model/dist/bindmodel.pack.min.js"></script> -->
<script src="/dist/bindmodel.pack.min.js"></script>
<script src="./App.js" type="module"></script>
</body>
</html>
app.js
import React from 'https://esm.sh/react';
import ReactDOM from 'https://esm.sh/react-dom';
import NoticeAdminPage from './components/NoticeAdminPage.js';
function App() {
return React.createElement(NoticeAdminPage);
}
ReactDOM.render(
React.createElement(App),
document.getElementById('root')
);
service/notice-admin-svc.js
class NoticeAdminService {
constructor(reactThis) {
const _this = this;
this.items = {
title: { required: true }
},
this.command = {
create: {
},
read: {
outputOption: 3,
},
update: {
cbBind(bind, cmd, setup) {
console.warn('Caution: Send to the test server, but the data is not reflected.', setup.data);
},
cbEnd(status, cmd, res) {
if (res) {
alert('The post has been modified.');
reactThis.handleList();
}
}
},
delete: {
cbValid(valid, cmd) {
if (confirm('Are you sure you want to delete it?')) return true;
},
cbBind(bind, cmd, setup) {
console.warn('Caution: Send to the test server, but the data is not reflected.', setup.data);
},
cbEnd(status, cmd, res) {
if (res) {
alert('The post has been deleted.');
reactThis.handleList();
}
}
},
list: {
outputOption: 1,
cbEnd(status, cmd, res) {
reactThis.setState({ selectedNotice: null });
}
}
};
this.mapping = {
ntc_idx: { read: ['bind', 'output'], update: 'bind', delete: ['valid', 'bind'] },
title: { read: 'output', update: ['valid', 'bind'], },
contents: { read: 'output', update: 'bind' },
top_yn: { read: 'output', update: ['valid', 'bind'], },
active_cd: { read: 'output', update: ['valid', 'bind'], },
create_dt: { read: 'output' },
};
this.fn = {
handleRead: async (idx) => {
_this.bindModel.cmd['read'].outputOption.index = Number(idx);
await _this.bindModel.cmd['read'].execute();
reactThis.setState({ selectedNotice: true });
},
};
}
}
export {
NoticeAdminService as default,
NoticeAdminService
}
components/NoticeAdminPage.js
import React, { Component } from 'https://esm.sh/react';
import NoticeList from './NoticeList.js';
import NoticeForm from './NoticeForm.js';
import NoticeAdminService from '../service/notice-admin-svc.js'
export default class NoticeAdminPage extends Component {
constructor(props) {
super(props);
this.bm = new _L.BindModel(new NoticeAdminService(this));
this.bm.url = '/notice/data/list.json';
this.state = { selectedNotice: null };
}
componentDidMount() {
this.bm.cmd['list'].execute();
}
handleList = () => {
this.setState({ selectedNotice: null });
};
handleChange = (e) => {
let { name, value, type, checked } = e.target;
if (type === 'checkbox') value = checked ? 'Y' : 'N';
this.bm.cols[name].value = value; // column value setting
this.forceUpdate(); // Forced screen rendering
};
render() {
const { selectedNotice } = this.state;
return (
React.createElement('div', { className: 'container mt-3' },
React.createElement('h2', null, 'Notice Admin Page'),
React.createElement('h5', null, 'Key Features: List inquiry/modification/deletion'),
React.createElement('p', null, 'Data is transmitted when modified or deleted from the test page, but it is not actually processed.'),
React.createElement(NoticeList, { bindModel: this.bm }),
!selectedNotice || (
React.createElement(NoticeForm, {
handleChange: this.handleChange,
bindModel: this.bm
})
)
)
);
}
}
components/NoticeForm.js
import React, { Component } from 'https://esm.sh/react';
export default class NoticeForm extends Component {
render() {
const { handleChange, bindModel } = this.props;
return (
React.createElement('div', { id: 'class-form' },
React.createElement('form', null,
React.createElement('div', { className: 'form-group' },
React.createElement('label', {}, '날짜'),
React.createElement('p', { id: 'create_dt' }, bindModel.cols.create_dt.value)
),
React.createElement('div', { className: 'form-group' },
React.createElement('label', { htmlFor: 'title' }, 'Title'),
React.createElement('input', {
type: 'text',
className: 'form-control',
id: 'title',
name: 'title',
value: bindModel.cols.title.value,
onChange: handleChange
})
),
React.createElement('div', { className: 'form-group' },
React.createElement('label', { htmlFor: 'contents' }, 'Content'),
React.createElement('textarea', {
className: 'form-control',
id: 'contents',
name: 'contents',
rows: '3',
value: bindModel.cols.contents.value,
onChange: handleChange
})
),
React.createElement('div', { className: 'row' },
React.createElement('div', { className: 'col' },
React.createElement('div', { className: 'form-check' },
React.createElement('input', {
type: 'checkbox',
className: 'form-check-input',
id: 'check1',
name: 'top_yn',
checked: bindModel.cols.top_yn.value === 'Y',
onChange: handleChange
}),
React.createElement('label', { className: 'form-check-label', htmlFor: 'check1' }, 'top notice')
)
),
React.createElement('div', { className: 'col' },
['D', 'A', 'H'].map(value => (
React.createElement('div', { className: 'form-check', key: value },
React.createElement('input', {
type: 'radio',
className: 'form-check-input',
id: `radio${value}`,
name: 'active_cd',
value: value,
checked: bindModel.cols.active_cd.value === value,
onChange: handleChange
}),
React.createElement('label', { className: 'form-check-label', htmlFor: `radio${value}` },
value === 'D' ? 'Standby' : value === 'A' ? 'Activation' : 'Hidden'
)
)
))
)
)
),
React.createElement('button', { type: 'button', className: 'btn btn-primary mt-3', onClick: ()=> bindModel.cmd['update'].execute() }, 'Update'),
React.createElement('button', { type: 'button', className: 'btn btn-primary mt-3', onClick: ()=> bindModel.cmd['delete'].execute() }, 'Delete'),
React.createElement('button', { type: 'button', className: 'btn btn-primary mt-3', onClick: ()=> bindModel.cmd['list'].execute() }, 'List')
)
);
}
}
components/NoticeList.js
import React, { Component } from 'https://esm.sh/react';
export default class NoticeList extends Component {
render() {
const { bindModel } = this.props;
const rows = bindModel.cmd.list.output.rows;
return (
React.createElement('table', { className: 'table' },
React.createElement('thead', null,
React.createElement('tr', null,
React.createElement('th', null, 'Title'),
React.createElement('th', null, 'Status'),
React.createElement('th', null, 'Date')
)
),
React.createElement('tbody', null,
rows.count > 0 ? (
rows.map((notice, i) => (
React.createElement('tr', { key: notice.ntc_idx },
React.createElement('td', null,
React.createElement('a', { href: '#', onClick: () => bindModel.fn.handleRead(i), className: 'btnNormal' },
notice.title
)
),
React.createElement('td', null, notice.active_cd),
React.createElement('td', null, notice.create_dt)
)
))
) : (
React.createElement('tr', null,
React.createElement('td', { colSpan: '3' }, 'There is no content.')
)
)
)
)
);
}
}