如何通过反应从数据库中获取正确的数据
Posted
技术标签:
【中文标题】如何通过反应从数据库中获取正确的数据【英文标题】:How can I get the right data from database with react 【发布时间】:2018-03-27 11:12:34 【问题描述】:我用nodejs+react+redux做了一个页面。 我在页面中做了一个编辑按钮,想编辑我的数据。
现在我选择 KUMAMOTO-CTI 并将优先级从 5 更改为 10。我使用 ajax 从数据库中获取数据以填补空白。在提交之前,我可以从数据库中获取正确的数据。但是当我更改优先级和点击再次编辑。填写的数据会出错。我必须刷新它才能得到正确的数据。
而且有时候会变成这样:Error
谁能告诉我怎么解决?
这是图片:progress
这是我的代码。
server.js
const Koa = require('koa')
const Router = require('koa-router')
const cors = require('koa2-cors')
const app = new Koa()
const router = new Router()
import createStore from 'redux'
import Provider from 'react-redux'
import serversReducer from '../client/reducers/reducer'
import renderToString from 'react-dom/server'
const store = createStore(serversReducer)
const views = require('koa-views')
const co = require('co')
const convert = require('koa-convert')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const debug = require('debug')('koa2:server')
const path = require('path')
//const ReactDOMServer = require('react-dom/server')
const React = require('react')
const config = require('./config')
const routes = require('./routes')
const mongoose = require('mongoose')
const stateSchema = require('./models/State')
const mission = require('./models/port')
const port = process.env.PORT || config.port
import Main from '../client/containers/Main'
mongoose.connect('mongodb://127.0.0.1:27017/monitor',
useMongoClient: true
);
mongoose.Promise = global.Promise;
var State = mongoose.model("State", stateSchema);
// error handler
onerror(app)
// middlewares
app.use(bodyparser())
.use(json())
.use(logger())
.use(cors())
.use(require('koa-static')(__dirname + '/public'))
.use(views(path.join(__dirname, '/views'),
options:
settings:
views: path.join(__dirname, 'views')
,
map:
'ejs': 'ejs'
,
extension: 'ejs'
))
.use(router.routes())
.use(router.allowedMethods())
// logger
app.use(async(ctx, next) =>
const start = new Date()
await next()
const ms = new Date() - start
console.log(`$ctx.method $ctx.url - $ms`)
)
router.get('/', async(ctx, next) =>
const staticMarkup = await renderToString(
<Provider store=store>
<Main />
</Provider>
)
const preloadedState = store.getState();
//console.log(preloadedState);
await ctx.render('index',
reduxData: preloadedState,
helloComponentMarkup: staticMarkup
)
)
router.post('/show', async(ctx, next) =>
ctx.body = 'ok';
let newArray = [];
await State.find(, function(err, doc)
if (err)
return;
doc.forEach(function(element, index)
newArray.push(element);
)
ctx.response.body = JSON.stringify(newArray);
).sort(
priority: 1
)
)
router.post('/edit', async(ctx, next) =>
ctx.body = 'ok'
await State.update(
_id: ctx.request.body.querymark
,
$set:
server_name: ctx.request.body.servername,
jp_name: ctx.request.body.jpname,
ip_address: ctx.request.body.ipaddress,
port: ctx.request.body.port,
priority: ctx.request.body.priority
, function(err, doc)
if (err)
return;
)
)
router.post('/create', async(ctx, next) =>
ctx.body = 'ok'
await new State(
server_name: ctx.request.body.servername,
jp_name: ctx.request.body.jpname,
ip_address: ctx.request.body.ipaddress,
port: ctx.request.body.port,
priority: ctx.request.body.priority
).save(function(err)
if (err)
console.log(err.toString());
)
)
router.post('/delete', async(ctx, next) =>
ctx.body = 'ok'
await State.remove(
_id: ctx.request.body.id
, function(err, doc)
if (err)
return;
);
)
routes(router)
app.on('error', function(err, ctx)
console.log(err)
logger.error('server error', err, ctx)
)
module.exports = app.listen(config.port, () =>
console.log(`Listening on http://localhost:$config.port`)
console.log(__dirname);
)
ListContainer.js
import React, Component from 'react'
import PropTypes from 'prop-types'
import connect from 'react-redux'
import Router, Route, hashHistory from 'react-router'
import Segment, Icon, Table, Modal, Button, Form from 'semantic-ui-react'
const axios = require('axios')
class ListContainer extends Component
static propTypes =
test_data: PropTypes.object.isRequired,
post_data: PropTypes.object.isRequired,
onDeleteServer: PropTypes.func,
onEditServer: PropTypes.func,
initServers: PropTypes.func,
index: PropTypes.number
constructor(props)
super(props)
this.state = (
servername: props.post_data.server_name,
jpname: props.post_data.jp_name,
ipaddress: props.post_data.ip_address,
port: props.post_data.port,
priority: props.post_data.priority
)
static defaultProps =
servers: []
handleDeleteServer(index)
if (this.props.onDeleteServer)
this.props.onDeleteServer(this.props.index)
else
console.log("error")
/*handleEditServer(index)
if (this.props.onEditServer)
this.props.onEditServer(this.props.index)
else
console.log("error")
this.setState(
open: false
)
*/
handleServerNameChange(event)
this.setState(
servername: event.target.value
)
handleJPNameChange(event)
this.setState(
jpname: event.target.value
)
handleIPChange(event)
this.setState(
ipaddress: event.target.value
)
handlePORTChange(event)
this.setState(
port: event.target.value
)
handlePriorityChange(event)
this.setState(
priority: event.target.value
)
handleSubmit(index)
axios.post('/edit',
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
).then((response) =>
var new_data;
if (response.data.success === false)
alert("error")
else
window.location.reload();
//console.log(this.props.post_data)
dispatch(onEditServer(index,
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
))
).catch(() =>
)
this.setState(
open: false
)
state =
open: false
show = (size, dimmer) => () => this.setState(
size,
dimmer,
open: true
)
close = () => this.setState(
open: false
)
render()
const open, size, dimmer = this.state
const post_data = this.props.post_data
var updated_time = (new Date(post_data.updated_at)).toLocaleString().replace('/T/', '').replace('/\../+', '')
var state_color = (post_data.state == "green") ? "green" : "red"
var icon_name = (post_data.state == "green") ? "smile" : "warning sign"
return (
<Table.Row>
<Table.Cell><Icon name=icon_name color=state_color/></Table.Cell>
<Table.Cell>post_data.jp_name</Table.Cell>
<Table.Cell>post_data.ip_address</Table.Cell>
<Table.Cell>post_data.port</Table.Cell>
<Table.Cell>updated_time</Table.Cell>
<Table.Cell>post_data.priority</Table.Cell>
<Table.Cell>
<div>
<Icon link name='settings' color='purple' onClick=this.show('small', 'blurring') />
<Modal size=size dimmer=dimmer open=open onClose=this.close closeIcon>
<Modal.Header>Edit</Modal.Header>
<Modal.Content>
<Modal.Description>
<Form>
<Form.Group width='equal'>
<Form.Field>
<label>Server Name</label>
<input value=this.state.servername onChange=this.handleServerNameChange.bind(this) />
</Form.Field>
<Form.Field>
<label>JP Name</label>
<input value=this.state.jpname onChange=this.handleJPNameChange.bind(this) />
</Form.Field>
</Form.Group>
<Form.Group width='equal'>
<Form.Field>
<label>IP Address</label>
<input value=this.state.ipaddress onChange=this.handleIPChange.bind(this) />
</Form.Field>
<Form.Field>
<label>Priority</label>
<input value=this.state.priority onChange=this.handlePriorityChange.bind(this) />
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field>
<label>Port</label>
<input value=this.state.port onChange=this.handlePORTChange.bind(this) />
</Form.Field>
</Form.Group>
</Form>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color='black' onClick=this.close>
Nope
</Button>
<Button positive icon='checkmark' labelPosition='right' content="Submit" onClick=this.handleSubmit.bind(this) />
</Modal.Actions>
</Modal>
</div>
</Table.Cell>
<Table.Cell><Icon link name='trash' color='purple' onClick=this.handleDeleteServer.bind(this) /></Table.Cell>
</Table.Row>
)
const mapStateToProps = (state) =>
return
servers: state.servers
const mapDispatchToProps = (dispatch) =>
return
onEditServer: (index, data) =>
dispatch(editServer(index, data))
,
export default connect(
mapStateToProps,
mapDispatchToProps
)(ListContainer)
SegmentContainer.js
import React, Component from 'react'
import PropTypes from 'prop-types'
import connect from 'react-redux'
import Container, Loader, Table, Grid, Icon, Button, Modal, Form from 'semantic-ui-react'
import SegmentList from '../components/SegmentContainer'
import initServers, deleteServer, editServer from '../reducers/reducer'
import MenuFix from '../components/Menu'
const axios = require('axios')
class SegmentContainer extends Component
static propTypes =
servers: PropTypes.array,
initServers: PropTypes.func,
onDeleteServer: PropTypes.func,
onAddServer: PropTypes.func
constructor()
super()
//this._loadData()
this.state =
servername: '',
jpname: '',
ipaddress: '',
priority: ''
componentWillMount()
this._loadData()
componentDidMount()
if (this.timer)
clearInterval(this.timer)
this.timer = setInterval(() =>
this._loadData()
, 3000)
componentWillUnmount()
clearInterval(this.timer)
_loadData()
let sorted_data = [];
let posts_data = [];
let response = axios.post('/show')
.then((response) =>
Object.keys(response.data).forEach(function(index)
sorted_data.push(response.data[index]);
)
function _dataCompare(a, b)
if (a.priority > b.priority)
return 1;
if (a.priority < b.priority)
return -1;
return 0;
sorted_data.forEach((item, index) =>
posts_data.push(item);
)
posts_data.sort(_dataCompare);
this.props.initServers(posts_data)
//dispatch(initServers(posts_data))
).catch(() =>
)
handleDeleteServer(index)
const servers = this.props
axios.post('/delete',
id: servers[index]._id
).then((response) =>
if (response.data.success === false)
alert("error");
else
window.location.reload();
).catch(() =>
)
if (this.props.onDeleteServer)
this.props.onDeleteServer(index)
/*handleEditServer(index)
const servers = this.props
axios.post('/edit',
querymark: this.props.servers._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
).then((response) =>
if (response.data.success === false)
alert("error")
else
//window.location.reload();
dispatch(onEditServer(index,
querymark: this.props.servers._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
))
).catch(() =>
)
this.setState(
open: false
)
*/
handleCreate(server)
axios.post('/create',
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
).then((response) =>
if (response.data.success === false)
alert("error");
else
window.location.reload()
dispatch(onAddServer(index,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
))
).catch(() =>
)
this.setState(
open: false
)
handleServerNameChange(event)
this.setState(
servername: event.target.value
)
handleJPNameChange(event)
this.setState(
jpname: event.target.value
)
handleIPChange(event)
this.setState(
ipaddress: event.target.value
)
handlePORTChange(event)
this.setState(
port: event.target.value
)
handlePriorityChange(event)
this.setState(
priority: event.target.value
)
state =
open: false
show = (size, dimmer) => () => this.setState(
size,
dimmer,
open: true
)
close = () => this.setState(
open: false
)
render()
const open, size, dimmer = this.state
return (
<Grid>
<MenuFix />
<Container style =
marginTop: '6em'
>
<Table unstackable>
<Table.Header>
<Table.Row>
<Table.HeaderCell colSpan='8'>
<Button basic color='violet' floated='right' icon labelPosition='left' primary size='tiny' onClick=this.show('small', 'blurring')>
<Icon link color='violet' name='add' />Add
</Button>
<Modal size=size dimmer=dimmer open=open onClose=this.close closeIcon>
<Modal.Header>Add</Modal.Header>
<Modal.Content>
<Modal.Description>
<Form>
<Form.Group width='equal'>
<Form.Field>
<label>Server Name</label>
<input value=this.state.servername onChange=this.handleServerNameChange.bind(this) />
</Form.Field>
<Form.Field>
<label>JP Name</label>
<input value=this.state.jpname onChange=this.handleJPNameChange.bind(this) />
</Form.Field>
</Form.Group>
<Form.Group width='equal'>
<Form.Field>
<label>IP Address</label>
<input value=this.state.ipaddress onChange=this.handleIPChange.bind(this) />
</Form.Field>
<Form.Field>
<label>Priority</label>
<input value=this.state.priority onChange=this.handlePriorityChange.bind(this) />
</Form.Field>
</Form.Group>
<Form.Group>
<Form.Field>
<label>Port</label>
<input value=this.state.port onChange=this.handlePORTChange.bind(this) />
</Form.Field>
</Form.Group>
</Form>
</Modal.Description>
</Modal.Content>
<Modal.Actions>
<Button color='black' onClick=this.close>
Nope
</Button>
<Button positive icon='checkmark' labelPosition='right' content="Submit" onClick=this.handleCreate.bind(this) />
</Modal.Actions>
</Modal>
</Table.HeaderCell>
</Table.Row>
<Table.Row>
<Table.HeaderCell>State<Loader active inline size='small' /></Table.HeaderCell>
<Table.HeaderCell>Server Name</Table.HeaderCell>
<Table.HeaderCell>IP Address</Table.HeaderCell>
<Table.HeaderCell>Port</Table.HeaderCell>
<Table.HeaderCell>Updated</Table.HeaderCell>
<Table.HeaderCell>Priority</Table.HeaderCell>
<Table.HeaderCell>Edit</Table.HeaderCell>
<Table.HeaderCell>Delete</Table.HeaderCell>
</Table.Row>
</Table.Header>
<SegmentList posts_data = this.props.servers onDeleteServer=this.handleDeleteServer.bind(this) />
</Table>
</Container>
</Grid>
)
const mapStateToProps = (state) =>
return
servers: state.servers
const mapDispatchToProps = (dispatch) =>
return
initServers: (servers) =>
dispatch(initServers(servers))
,
onDeleteServer: (index) =>
dispatch(deleteServer(index))
,
onEditServer: (index, data) =>
dispatch(editServer(index, data))
,
onAddServer: (server) =>
dispatch(addServer(server))
export default connect(
mapStateToProps,
mapDispatchToProps
)(SegmentContainer)
reducer.js
//action types
const INIT_SERVERS = 'INIT_SERVERS'
const ADD_SERVER = 'ADD_SERVER'
const DELETE_SERVER = 'DELETE_SERVER'
const EDIT_SERVER = 'EDIT_SERVER'
//reducer
export default function(state, action)
if (!state)
state =
servers: []
switch (action.type)
case INIT_SERVERS:
return
servers: action.servers
case ADD_SERVER:
return
servers: [...state.servers, action.server]
case EDIT_SERVER:
return
servers: [...state.servers.slice(0, action.index), Object.assign(, state.servers[action.index],
done: true
), ...state.servers.slice(action.index + 1)]
/*servers: Object.assign([...state.servers],
[index]: action.data
)*/
//servers: Object.assign(, state[action.index], action.data)
case DELETE_SERVER:
return
servers: [
...state.servers.slice(0, action.index),
...state.servers.slice(action.index + 1)
]
default:
return state
// action creators
export const initServers = (servers) =>
return
type: INIT_SERVERS,
servers
export const addServer = (server) =>
return
type: ADD_SERVER,
server
export const deleteServer = (index) =>
return
type: DELETE_SERVER,
index
export const editServer = (index, data) =>
return
type: EDIT_SERVER,
index,
data
SegmentList.js
import React, Component, PropTypes from 'react'
import ListContainer from '../containers/ListContainer'
export default class SegmentList extends Component
static propTypes =
posts_data: PropTypes.array,
onDeleteServer: PropTypes.func,
//onEditServer: PropTypes.func
static defaultProps =
posts_data: []
handleDeleteServer(index)
if (this.props.onDeleteServer)
this.props.onDeleteServer(index)
/*handleEditServer(index)
if (this.props.onEditServer)
this.props.onEditServer(index)
*/
render()
return (
<div>
this.props.posts_data.map((data, i) => <ListContainer
post_data=data
key=i
index=i onDeleteServer=this.handleDeleteServer.bind(this) />
)
</div>
)
【问题讨论】:
【参考方案1】:首先,react 是针对 SPA 的,如果您使用 reload,只需使用 HTTP(无 ajax)进行编辑。这是SPA的解决方案
在编码之前,主要思想是在编辑后更新你的数据,所以路线图应该是:
1.从服务器获取一个数组并存储到state.servers
,它应该是一个包含你的服务器信息的普通对象列表
2.当你更新时,你应该将更新应用到服务器,然后更新到本地存储,就像你在创建/删除中所做的那样,编辑很可能与更多数据相同
那么你的handleSubmit
应该是(注意迭代中的索引作为参数)
//index from iteration, should be passed from parent component
handleSubmit(index)
const data =
querymark: this.props.post_data._id,
servername: this.state.servername,
jpname: this.state.jpname,
ipaddress: this.state.ipaddress,
port: this.state.port,
priority: this.state.priority
axios.post('/edit', data).then((response) =>
if (response.data.success === false)
alert("error");
else
//window.location.reload();
dispatch(onEditServer(index,data))
).catch(() => )
this.setState(
open: false
)
onEditServer
应该是
const mapDispatchToProps = (dispatch) =>
return
initServers: (servers) =>
dispatch(initServers(servers))
,
onDeleteServer: (serverIndex) =>
dispatch(deleteServer(serverIndex))
,
onEditServer: (index, data) =>
dispatch(editServer(
type: 'edit',
index,
data,
))
,
onAddServer: (server) =>
dispatch(addServer(server))
编辑减速器
// edit reducer
const edit = (state, action)
state.servers[action.index] = actions.data
return state
然后更改将自动生效
【讨论】:
谢谢。根据您的评论,我编辑了我的代码,但仍然有同样的问题。我编辑了我的问题。你能告诉我哪里出错了吗? @RunChickenonEditServer
, data
里面 dispatch(onEditServer(index, data))
没有分配,不是吗?我会将这些代码背后的想法更新为我的答案
我可以看到变化,但是当我想再次编辑相同的数据时,它无法获得正确的数据。
如果您的意思是其他人可能会更改数据,那么您需要在您的服务器信息中提供一个版本并同时处理后端和前端
case EDIT_SERVER: return servers: [...state.servers, state.servers[action.index] = action.data]
这不是将数据分配给正确的索引,如果您希望它更不可变 return [...state.slice(0, action.index), Object.assign(, state[action.index], done: true), ...state.slice(action.index + 1)]
或只是 Object.assign
将起作用以上是关于如何通过反应从数据库中获取正确的数据的主要内容,如果未能解决你的问题,请参考以下文章