2017-09-02 10 views
0

Reactでリストコンポーネントを作成しましたが、2つの目立つ問題が発生しました。Reactコンポーネント/ビューでDOMとデータベースを同期する方法

  1. 項目が削除されるものの、それが唯一のリフレッシュ時に反映されている(だけでなく、データベースから)の項目がリストから削除されているときは、リスト#または減算しないID列を気づいているかもしれません

私はバックエンドでPostgreSQLを使用しています。オブジェクト/リレーショナルマッパーとしてSequelizeを使用しています。

私はgifを提供していますので、皆さんは私が何を意味するのか見ることができます。

ありがとうございます!

が反応: Student.js

import React, { Component } from "react"; 
import store from "../store"; 
import { deleteStudent } from "../reducers"; 

export default class Students extends Component { 
    constructor(props) { 
    super(props); 
    this.state = store.getState(); 
    this.deleteStudent = this.deleteStudent.bind(this); 
    } 

    componentDidMount() { 
    this.unsubscribe = store.subscribe(() => { 
     this.setState(store.getState()); 
    }); 
    } 

    componentWillUnmount() { 
    this.unsubscribe(); 
    } 

    deleteStudent(index) { 
    store.dispatch(deleteStudent(index)); 
    this.state = store.getState(); 
    } 

    render() { 
    var students = this.props.students; 
    return (
     <div className="container"> 
     <div className="sixteen columns"> 
      <h1 className="remove-bottom">Students</h1> 
      <h5>List of current students and their campus</h5> 
      <hr /> 
     </div> 
     <div className="sixteen columns"> 
      <div className="example"> 
      <div> 
       <table className="u-full-width"> 
       <thead> 
        <tr> 
        <th>#</th> 
        <th>Name</th> 
        <th>Email</th> 
        <th>Campus</th> 
        </tr> 
       </thead> 
       <tbody> 
        {students.map(function(student, index) { 
        return (
         <tr key={index}> 
         <td> 
          {student.id} 
         </td> 
         <td> 
          {student.name} 
         </td> 
         <td> 
          {student.email} 
         </td> 
         <td> 
          {student.campus} 
         </td> 
         <td> 
          <a 
          className="button button-icon" 
          onClick={() => { 
           console.log(student.id); 
           this.deleteStudent(student.id); 
          }} 
          key={index} 
          > 
          <i className="fa fa-remove" /> 
          </a> 
         </td> 
         </tr> 
        ); 
        }, this)} 
       </tbody> 
       </table> 
      </div> 
      </div> 
     </div> 
     </div> 
    ); 
    } 
} 

マイリデューサー:

この

は私のコードです

import { combineReducers } from "redux"; 
import axios from "axios"; 

const logError = console.error.bind(console); 

// INITIAL STATE 

const initialState = { 
    students: [], 
    campuses: [] 
}; 

//ACTION CREATORS 

const UPDATE_NAME = "UPDATE_NAME"; 
const ADD_STUDENT = "ADD_STUDENT"; 
const DELETE_STUDENT = "DELETE_STUDENT"; 
const GET_STUDENTS = "GET_STUDENTS"; 
const UPDATE_CAMPUS = "UPDATE_CAMPUS"; 
const GET_CAMPUS = "GET_CAMPUS"; 
const GET_CAMPUSES = "GET_CAMPUSES"; 

// ACTION CREATORS 

export function updateName(name) { 
    const action = { 
    type: UPDATE_NAME, 
    name 
    }; 
    return action; 
} 

export function addStudent(student) { 
    return { 
    type: ADD_STUDENT, 
    student 
    }; 
} 

export function scrubStudent(student) { 
    return { 
    type: DELETE_STUDENT, 
    student 
    }; 
} 

export function getStudents(students) { 
    const action = { 
    type: GET_STUDENTS, 
    students 
    }; 
    return action; 
} 

export function updateCampus(campus) { 
    const action = { 
    type: UPDATE_CAMPUS, 
    campus 
    }; 
    return action; 
} 

export function getCampus(campus) { 
    const action = { 
    type: GET_CAMPUS, 
    campus 
    }; 
    return action; 
} 

export function getCampuses(campuses) { 
    const action = { 
    type: GET_CAMPUSES, 
    campuses 
    }; 
    return action; 
} 

//THUNK CREATORS 

export function fetchStudents() { 
    return function thunk(dispatch) { 
    return axios 
     .get("/api/students") 
     .then(function(res) { 
     return res.data; 
     }) 
     .then(students => { 
     dispatch(getStudents(students)); 
     }) 
     .catch(logError); 
    }; 
} 

export function postStudent(student) { 
    return function thunk(dispatch) { 
    return axios 
     .post("/api/students", student) 
     .then(function(res) { 
     return res.data; 
     }) 
     .then(function(newStudent) { 
     return dispatch(addStudent(newStudent)); 
     }) 
     .catch(logError); 
    }; 
} 

export function deleteStudent(id) { 
    // console.log("student", student); 
    return function thunk(dispatch) { 
    return axios 
     .delete("/api/students" + "/" + id) 
     .then(function(id) { 
     return dispatch(scrubStudent(id)); 
     }) 
     .catch(function(err) { 
     return console.error("Removing student: " + id + " unsuccessful", err); 
     }); 
    }; 
} 

export function fetchCampuses() { 
    return function thunk(dispatch) { 
    return axios 
     .get("/api/campuses") 
     .then(function(res) { 
     return res.data; 
     }) 
     .then(function(campuses) { 
     return dispatch(getCampuses(campuses)); 
     }) 
     .catch(logError); 
    }; 
} 

export function postCampus(student) { 
    return function thunk(dispatch) { 
    return axios 
     .post("/api/campuses", campus) 
     .then(function(res) { 
     return res.data; 
     }) 
     .then(function(newCampus) { 
     return dispatch(getCampus(newCampus)); 
     }) 
     .catch(logError); 
    }; 
} 

// REDUCER 

const rootReducer = function(state = initialState, action) { 
    var newState = Object.assign({}, state); 

    switch (action.type) { 
    case GET_STUDENTS: 
     newState.students = state.students.concat(action.students); 
     return newState; 

    case ADD_STUDENT: 
     newState.students = state.students.concat([action.student]); 
     return newState; 

    case DELETE_STUDENT: 
     console.log("action.student", action.student); 
     console.log("state", state); 
     state.filter(function(student) { 
     return student.id !== action.id; 
     }); 
     return newState; 

    case GET_CAMPUSES: 
     newState.campuses = state.campuses.concat(action.campuses); 
     return newState; 

    case GET_CAMPUS: 
     newState.campuses = state.campuses.concat([action.campus]); 
     return newState; 

    default: 
     return state; 
    } 
}; 

export default rootReducer; 

そして、これは私の学生モデルである:

'use strict'; 
var Sequelize = require('sequelize') 
var db = require('../index.js') 

//hasOne, hasMany, belongsTo, belongsToMany Sequelize methods 

module.exports = db.define('student', { 
    name: { 
    type: Sequelize.STRING, 
    allowNull: false, 

    }, 

    email: { 
    type: Sequelize.STRING, 
    allowNull: false, 
    unique: true, 
    validate: { 
     isEmail: true 
    } 
    }, 

    campus: { 
    type: Sequelize.STRING, 
    allowNull: false, 

    } 
}) 

enter image description here

+0

を作成するために、あなたのコンポーネントに接続する機能を使用して起動する必要がありますが、 'だけでなく' this.state'を割り当てるのでsetState'呼び出す必要はありませんでしょうか? – Mikkel

+0

@Mikkel Where ?? –

+0

ねえ、実際にあなたのことがうまくいかないことがたくさんあります。あなたは正しい方向に向かっています。私は助けたいと思っています、あなたはどこかでgit repoでこれを持っていますか?student.jsの –

答えて

0

私はこれに答えたいと思いますが、これに欠けている部分が少しあります。私はあなたがGITのレポにそれを置き、そのように多くの助けを必要とすると思います。

最初に行う必要があることは、適切なストア設定/ビルドを作成することです。以下のようなもの...

import { createStore, applyMiddleware, compose } from 'redux' 
import thunk from 'redux-thunk' 
import createLogger from 'redux-logger' 
import baseMiddleware from 'redux/middleware/' 
import reducer from 'redux/modules/reducer' 
import { routerMiddleware } from 'react-router-redux' 
import { persistState } from 'redux-devtools'; 

export default function configureStore(initialState, history) { 
    const middleware = baseMiddleware.with(thunk, createLogger(), routerMiddleware(history)) 

    const store = createStore(
     reducer, 
     initialState, 
     compose(
      applyMiddleware(...middleware), 
      window.devToolsExtension ? window.devToolsExtension() : f => f, 
      persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)) 
     ) 
    ) 

    if (module.hot) { 
     // Enable Webpack hot module replacement for reducers 
     module.hot.accept('redux/modules/reducer',() => { 
      const nextRootReducer = require('redux/modules/reducer').default 
      store.replaceReducer(nextRootReducer) 
     }) 
    } 

    return store 
} 

これは2つのメインファイルを参照しています。 1つは減速機用、もう1つはミドルウェア用です。それはSOLID

のSにこの私のミドルウェアです...

import api from './api' 
import authenticationMiddleware from './authenticationMiddleware' 
import analyticsMiddleware from './analyticsMiddleware' 

const middleware = [ api, analyticsMiddleware, authenticationMiddleware ] 

export default { 
    with(){ 
     for(let i = 0; i < arguments.length; i++){ 
      middleware[middleware.length] = arguments[i]; 
     } 

     return middleware 
    }, 
    ...middleware 
} 

と減速

import { combineReducers } from 'redux'; 
import { routerReducer } from 'react-router-redux'; 

import {reducer as form} from 'redux-form'; 

import authentication from './authentication' 

const reducer = combineReducers({ 
    router: routerReducer, 
    authentication 
}) 

export default reducer 

に合ったあなたは、あなたのルートコンポーネントにお店に渡すことができますので、これは重要であり、プロバイダの上位コンポーネントを使用してオブジェクトグラフにReduxコンテキストを追加する

import React, { Component, PropTypes } from 'react' 
import { Provider } from 'react-redux' 
import routes from '../routes' 
import { Router } from 'react-router' 

export default class Root extends Component { 
    render() { 
    const { store, history } = this.props 
    return (
     <Provider store={store}> 
     <div> 
      <Router history={history} routes={routes} /> 
     </div> 
     </Provider> 
    ) 
    } 
} 

Root.propTypes = { 
    store: PropTypes.object.isRequired, 
    history: PropTypes.object.isRequired 
} 

ここで、店舗をルートコンポーネントに渡す方法はあなたの方が多く、過去の履歴を選択するよりも、最後の部分を残しておきます。

また、容器

+0

答えを読んでください。GitHubで作成したものをプルしました。npmは 'react-lifecycle-component'をインストールしましたが、今は' Uncaught TypeError:プロパティを読み込めません 'という学生StudentsViewの17行目の 'of null'を残して申し訳ありません私たちが一緒にやっていたことの詳細な説明を求めていたはずです。 –

関連する問題