I have created a list component in React but having trouble with two glaring problems.
I am using PostgreSQL on the backend and Sequelize as my Object/Relational Mapper and React for my views/components.
I have provided a gif so you all can see what I mean.
Thanks in advance!
This is my code:
React: 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>
);
}
}
My Reducer:
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;
And this is my Student Model:
'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,
}
})
I want to answer this but there is a bit to much that your missing in this. I think you need to place it in a GIT repo and get more help that way.
first thing you need to do is to create a proper store configuration/build. Something akin to the below...
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
}
This references two main files. One for my reducers and the other for my middleware. This is important because it fits into the S of SOLID
This is my middleware...
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
}
and reducers
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
You can then pass in your store into your root component and use Provider higher order component to then add the Redux context to the object graph
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
}
Now how you pass in the store to the Root component is more on you and wether you choose to have history, i'll leave that last part up to you.
You will also need to start using the Connect function on your components to create containers
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.