2017-09-04 47 views
0

我是React和Redux的新手,剛開始習慣於管理狀態和React。我前言說,因爲我可能需要可能的解決方案來處理我所擁有的內容 - 基本上我會更好地理解它。 :)如何在我的商店/狀態中刪除商品後,如何在React與Redux中刪除商品後我的視圖更新

話雖這麼說,這是我的問題:

我已經創造了反應,但有兩個明顯的問題,麻煩列表/表單組件。

雖然項目獲取數據庫中刪除, 它僅僅體現在一旦刷新視圖 您可能已經注意到列表#或在將項目從列表中刪除ID列不會減。 我在後端使用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.setState(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> 
    ); 
    } 
} 

StudentForm.js

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

const blankFormState = { 
    name: "", 
    email: "", 
    campus: "" 
}; 

export default class StudentForm extends Component { 
    constructor(props) { 
    super(props); 
    this.state = blankFormState; 
    this.handleChange = this.handleChange.bind(this); 
    this.handleSubmit = this.handleSubmit.bind(this); 
    } 

    handleChange(event) { 
    const target = event.target; 
    this.setState({ 
     [target.name]: target.value 
    }); 
    } 

    handleSubmit(event) { 
    event.preventDefault(); 
    store.dispatch(postStudent(this.state)); 
    this.setState(blankFormState); 
    } 

    render() { 
    return (
     <div className="container"> 
     <div className="row"> 
      <div className="twelve columns"> 
      <form onSubmit={this.handleSubmit}> 
       <div className="row"> 
       <div className="four columns"> 
        <label>Name</label> 
        <input 
        className="u-full-width" 
        type="text" 
        name="name" 
        value={this.state.name} 
        onChange={this.handleChange} 
        /> 
       </div> 
       <div className="four columns"> 
        <label>Email</label> 
        <input 
        className="u-full-width" 
        type="text" 
        name="email" 
        value={this.state.email} 
        onChange={this.handleChange} 
        /> 
       </div> 
       <div className="four columns"> 
        <label>Campus</label> 
        <input 
        className="u-full-width" 
        type="text" 
        name="campus" 
        value={this.state.campus} 
        onChange={this.handleChange} 
        /> 
       </div> 
       </div> 
       <input className="button-primary" type="submit" /> 
      </form> 
      </div> 
     </div> 
     </div> 
    ); 
    } 
} 

reducer.js

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); 
     newState = state.students.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; 

這是我如何安裝StudentsStudentForm

import React, { Component } from "react"; 
import Students from "./Students"; 
import StudentForm from "./StudentForm"; 
import store from "../store"; 

import { fetchStudents } from "../reducers"; 

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

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

    componentWillUnmount() { 
    this.unsubscribe(); 
    } 

    render() { 
    return (
     <div> 
     <Students students={this.state.students} /> 
     <StudentForm /> 
     </div> 
    ); 
    } 
} 

store.js

import { createStore, applyMiddleware } from "redux"; 
import rootReducer from "./reducers"; 
import createLogger from "redux-logger"; // https://github.com/evgenyrodionov/redux-logger 
import thunkMiddleware from "redux-thunk"; // https://github.com/gaearon/redux-thunk 

export default createStore(
    rootReducer, 
    applyMiddleware(thunkMiddleware, createLogger()) 
); 

enter image description here

+0

您能展示如何以及在哪兒安裝'Students'? – Panther

+0

@Panther,是的,如果我這樣做會有幫助。我剛剛更新了它。 –

+0

很酷。你也可以顯示你的'store.js'嗎? – Panther

回答

1

刪除學生你分派行動後,你是路過動作創建者scrubStudent發送。您正在將該刪除的學生的ID傳遞給該動作創建者。現在您已經定義了你的行動創造者的方式是這樣的

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

所以這個函數的返回值將是一個對象是這樣的

scrubStudent(5) // returns {type: "DELETE_STUDENT", student: 5} 

但在你減速你是比較喜歡的ID這

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

在上面的代碼action.id是未定義的。相反,學生ID保存爲action.student。所以比較將對數組的所有元素返回true。所以每次所有的元素都將被包含在新的狀態中。因此,請嘗試更改您的上述代碼,如下所示:

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

謝謝您的幫助。但是這個觀點並沒有更新。在做了一個'console.log('action.id',action.id)''我可以看到你是對的,我在那裏比較'未定義'。但事後我意識到'action.student'上沒有'id'屬性那麼我們爲什麼要比較呢? –

+0

當你在後端結果返回後發送動作時,你正在傳遞學生的'id',從後端返回,如'return dispatch(scrubStudent(id));'。所以如果你的後端正在返回被刪除的學生的id,那麼'action.student'會包含這個id。 –

+1

@ AntonioPavicevac-Ortiz另外我看到你正在使用store.getState()無處不在。我會推薦使用react-redux庫[http://redux.js.org/docs/basics/UsageWithReact.html]。當你將組件連接到這個庫時,只要你的狀態改變,你的視圖就會自動更新。 –

相關問題