[英]How to sync the DOM and Database in a React Component/View
我已經在React中創建了一個列表組件,但是遇到了兩個明顯的問題。
我在后端使用PostgreSQL,並將Sequelize用作我的視圖/組件的對象/關系映射器和React。
我提供了一個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,
}
})
我想回答這個問題,但是您在此方面有很多不足。 我認為您需要將其放入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
}
這引用了兩個主要文件。 一個用於我的減速器,另一個用於我的中間件。 這很重要,因為它適合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
然后,您可以將商店傳遞到根組件中,並使用Provider高階組件將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
}
現在,如何將存儲傳遞到Root組件的方法更多,並且您選擇擁有歷史記錄,我將最后一部分交給您。
您還需要開始在組件上使用Connect函數來創建容器
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.