React+Expressで掲示板を作成しています。
本の通りコードを書いていましたが、 node bbs-server.js
でlocalhostを立ち上げてみても、render()の中身が表示されません。
エラーにはTypeError: Cannot read property 'map' of undefined
と出てきます。
index.jsの
render(){
const itemsHtml = this.state.items.map(e => (
<li key={e._id}>{e.name} - {e.body}</li>
))
に原因があると思いますが、どこをどう直せば良いか分かりません。ご回答宜しくお願い致します。
使用しているツール
Node.js
Express
React
NeDB/SuperAgent
作成したプロジェクトのソースコードです。
package.json
{
"name": "bbs",
"version": "1.0.0",
"description": "",
"private": true,
"main": "bundle.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"nedb": "^1.8.0",
"superagent": "^5.1.0"
},
"devDependencies": {
"@babel/core": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/preset-react": "^7.0.0",
"babel-loader": "^8.0.6",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"webpack": "^4.38.0",
"webpack-cli": "^3.3.6"
}
}
webpack.config.js
const path = require('path');
module.exports = {
mode: 'production',
entry: path.join(__dirname,'src/index.js'),
output: {
path: path.join(__dirname,'public'),
filename: 'bundle.js'
},
devtool: 'inline-source-map',
module: {
rules: [{
test: /\.(js|jsx)$/,
use: [
{
loader: "babel-loader",
options: {
presets: ["@babel/preset-env","@babel/react"]
}
}
]
}]
}
};
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import request from 'superagent';
class BBSForm extends React.Component{
constructor(props){
super(props)
this.state = {
name: '',
body: ''
}
}
nameChanged(e){
this.setState({name: e.target.value})
}
bodyChanged(e){
this.setState({body: e.target.value})
}
//write post
post(e){
request
.get('/api/write')
.query({
name: this.state.name,
body: this.state.body
})
.end((err,data) => {
if(err){
console.error(err)
}
this.setState({body: ''})
if(this.props.onPost){
this.props.onPost()
}
})
}
render(){
return(
<div>
<label>名前: <br /></label>
<input type='text' value={this.state.name} onChange={e => this.nameChanged(e)} />
<br />
<label>本文: <br /></label>
<input type='text' value={this.state.body} size='60' onChange={e => this.bodyChanged(e)} />
<br />
<button onClick={e => this.post()}>発言する</button>
</div>
)
}
}
class BBSApp extends React.Component{
constructor(props){
super(props)
this.state = {
items: []
}
}
componentWillMount(){
this.loadLogs()
}
loadLogs(){
request
.get('/api/getItems')
.end((err,data) => {
if(err){
console.error(err)
return
}
this.setState({items: data.body.logs})
})
}
render(){
const itemsHtml = this.state.items.map(e => (
<li key={e._id}>{e.name} - {e.body}</li>
))
return(
<div>
<h1>掲示板</h1>
<BBSForm onPost={e => this.loadLogs()} />
<p><button onClick={e => this.loadLogs()}>再読み込み</button></p>
<ul>{itemsHtml}</ul>
</div>
)
}
}
ReactDOM.render(
<BBSApp />,
document.getElementById('root')
)
bbs-server.js
//bbs web server
const NeDB = require('nedb');
const path = require('path');
const db = new NeDB({
filename: path.join(__dirname,'bbs.db'),
autoload: true
});
const doc = {
name: "author",
body: "test"
}
db.insert(doc,function(err,newdoc){
console.log(newdoc._id)
})
db.loadDatabase();
//open server
const express = require('express');
const app = express();
const portNo = 3001;
app.listen(portNo,() => {
console.log('Open Server', `http://localhost:${portNo}`);
})
app.use('/public', express.static('./public'))
app.get('/', (req,res) => {
res.redirect(302,'/public')
})
//API
app.get('/api/getItems', (req,res) => {
db.find({}).sort({stime: 1}).exec((err,data) => {
if(err){
sendJSON(res,false,{logs: [],msg: err})
return
}
console.log(data)
sendJSON(res,true,{logs: data})
})
})
//new LOG
app.get('/api/write', (req,res) => {
const q = req.query
db.insert({
name: q.name,
body: q.body,
stime: (new Date()).getTime()
},(err,doc) => {
if(err) {
console.error(err)
sendJSON(res,false,{msg: err})
return
}
sendJSON(res,true,{id: doc._id})
})
})
function sendJSON(res,result,obj){
obj['result'] = result
res.json('obj')
}
質問は以上です。ご回答宜しくお願い致します。