如何通过反应从数据库中获取正确的数据

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

然后更改将自动生效

【讨论】:

谢谢。根据您的评论,我编辑了我的代码,但仍然有同样的问题。我编辑了我的问题。你能告诉我哪里出错了吗? @RunChicken onEditServer , 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 将起作用

以上是关于如何通过反应从数据库中获取正确的数据的主要内容,如果未能解决你的问题,请参考以下文章

Json 服务器数据在反应中未正确获取

如何在反应中正确获得axios响应?

如何在本机反应中从平面列表中设置 Json 数组

如何从反应上下文中获取数据

我如何从反应中获取消息后数据?

如何在反应应用程序中从数据库中获取和显示图像