Cannot receive and display props in React component - javascript

Im my MERN application a have a problem on frontend side. When I make a GET-request on backend on /params address, I can get a json-object in response:
current: 2
date: "2021-10-01T07:00:32.524Z"
power: 7.2
soc: 100
temperature: 20.5
voltage: 3.6
__v: 0
_id: "6156b21021e67919047727c7"
Whether the object is actually received and GET_PARAMS action is dispatched, I can make sure using console.log() in reducer file:
import {
GET_PARAMS,
PARAMS_ERROR,
CLEAR__PARAMS
} from '../actions/types';
const initialState = {
params: null,
loading: true,
exist: true,
error: {}
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case GET_PARAMS:
return {
...state,
params: payload,
loading: false,
exist: true
};
case PARAMS_ERROR:
return {
...state,
error: payload,
loading: false,
params: null,
exist: false
};
case CLEAR__PARAMS:
return {
...state,
params: null,
loading: false,
exist: true
};
default:
return state;
}
}
But when I run the application, I can see only empty placeholders in React component because of undefined values of props:
import React, { Fragment, useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Spinner from '../layout/Spinner';
import NotFound from '../layout/NotFound';
import { getParams } from '../../actions/params';
import { withRouter } from 'react-router-dom';
const Params = ({getParams, params: { voltage, current, power, soc, temperature, date }, loading, exist,
auth }) => {
console.log(voltage); //undefined
useEffect(() => {
getParams();
}, [getParams]);
return (
<Fragment>
<h1>ESP8266 Aspil Web Server</h1>
<table className="table">
<tbody>
<tr>
<td className="hide-sm"><h3>Time: </h3> </td>
<td className="hide-sm"><h3 id="time">{date}</h3></td>
</tr>
<tr>
<td className="hide-sm"><h3>Voltage: </h3></td>
<td className="hide-sm"><h3 id="voltage">{voltage} V</h3></td>
</tr>
<tr>
<td className="hide-sm"><h3>Current: </h3></td>
<td className="hide-sm"><h3 id="current">{current} A</h3></td>
</tr>
<tr>
<td className="hide-sm"><h3>Power: </h3></td>
<td className="hide-sm"><h3 id="power">{power} W</h3></td>
</tr>
<tr>
<td className="hide-sm"><h3>SOC: </h3></td>
<td className="hide-sm"><h3 id="soc">{soc}%</h3></td>
</tr>
<tr>
<td className="hide-sm"><h3>Temperature: </h3></td>
<td className="hide-sm"><h3 id="temperature">{temperature} oC</h3></td>
</tr>
</tbody>
</table>
</Fragment>
)
};
Params.propTypes = {
params: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
getParams: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
params: state.params,
auth: state.auth,
loading: state.loading,
exist: state.exist
});
export default connect(mapStateToProps, { getParams })(Params);
Why is it going wrong?

To display the data in your table you should use .map() as you are fetching data from backend. So with .map() it is going to take all you data and individually it will display the feilds that you want to.
SO I am just assuming you have code I am writing below.
Data returned from the backend:
current: 2
date: "2021-10-01T07:00:32.524Z"
power: 7.2
soc: 100
temperature: 20.5
voltage: 3.6
__v: 0
_id: "6156b21021e67919047727c7"
action
export const getAllData = () => async dispatch => {
const response = await axios.get("/params");
dispatch({ type: GET_PARAMS, payload: response.data });
};
reducer
import {
GET_PARAMS,
PARAMS_ERROR,
CLEAR__PARAMS
} from '../actions/types';
const initialState = {
params: null,
loading: true,
exist: true,
error: {}
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case GET_PARAMS:
return {
...state,
params: payload,
};
case PARAMS_ERROR:
return {
...state,
error: payload,
loading: false,
params: null,
exist: false
};
case CLEAR__PARAMS:
return {
...state,
params: null,
loading: false,
exist: true
};
default:
return state;
}
}
As I have no idea how you are getting data from backend to front end. Don't know what is the value of this.props so I am assuming its more or less code below.
component
import React, { Component } from "react";
import Container from '#material-ui/core/Container';
import { connect } from "react-redux";
import Table from '#material-ui/core/Table';
import TableCell from '#material-ui/core/TableCell';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import TableBody from '#material-ui/core/TableBody';
import TableContainer from '#material-ui/core/TableContainer';
import { getAllData} from "./actions";
class Params extends Component {
constructor() {
super();
this.state = {
skip: 0,
limit: 10,
pageNumber: 0,
value: ''
};
}
componentDidMount() {
this.props.getAllData();
}
render() {
return (
<div>
<div/>
<Container>
<TableContainer>
<Table aria-label="enhanced table">
<TableHead>
<TableRow>
<TableCell>Time</TableCell>
<TableCell>Voltage</TableCell>
<TableCell>Current</TableCell>
<TableCell>Power</TableCell>
<TableCell>SOC</TableCell>
<TableCell>Temperature</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.props.params.map((busObj, index) => {
return (
<TableRow>
<TableCell> {busObj.date} </TableCell>
<TableCell >{busObj.voltage}</TableCell>
<TableCell>{busObj.current}</TableCell>
<TableCell >{busObj.power}</TableCell>
<TableCell>{busObj.soc}</TableCell>
<TableCell>{busObj.temperature}</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</TableContainer>
</Container>
</div>
);
}
}
Params.propTypes = {
params: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
getParams: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
params: state.params,
auth: state.auth,
loading: state.loading,
exist: state.exist
});
export default connect(mapStateToProps, { getParams })(Params);
This can be more or less what you want. I hope this is what your looking for.

Related

TypeError: Cannot read property 'map' of undefined and a walk around

there is an object contactBook defined as below. I send it to redux and get it back in the exactly same format.
{“Book1” : [{name: “Bob”},{name, “Jane”}, {name, “Mary”]}
I intended to transfer it to a name list
import React, {Component} from 'react'
import {bindActionCreators} from "redux";
import * as actions from "../redux/actions";
import {withRouter} from 'react-router'
import {connect} from 'react-redux'
class ListContactComponent extends Component {
constructor(props) {
super(props);
this.state = {
message: null
};
}
componentDidMount() {
this.props.startLoadingContacts(this.props.match.params.bookName);
}
addContactClicked = () => {
this.props.history.push({
pathname: `/addressBook/contact/`,
state: this.state.bookName
})
};
render() {
let contacts = Object.values(this.props.contacts).flat();
return (
<div className="container">
<h3>All Contacts</h3>
{this.state.message && <div class="alert alert-success">{this.state.message}</div>}
<div className="container">
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Phone Number</th>
</tr>
</thead>
<tbody>
{
contacts.map(
(contact, index) =>
<tr key={index}>
<td>{contact.name}</td>
<td>{contact.phoneNumber}</td>
</tr>
)
}
</tbody>
</table>
<div className="row">
<button className="btn btn-success" onClick={this.addContactClicked}>Add</button>
</div>
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
contacts: state.contacts
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(actions, dispatch)
}
const connectedContactList = withRouter(connect(mapStateToProps, mapDispatchToProps)(ListContactComponent));
export {connectedContactList as ListContactComponent};
if I use:
contacts = contactsBook[Book1]
I got TypeError: Cannot read property 'map' of undefined
what’s the cause of this error, and how to fix it?
if I don't use the objected returned from redux, it just works fine. I don't really know what's difference?
Actions:
export function startLoadingContacts(addressBookName) {
return (dispatch) => {
return AddressBookDataService
.retrieveContacts(addressBookName)
.then(
(response) => {
let contacts = {};
contacts[addressBookName] = response.data;
dispatch(loadContacts(contacts))
}).catch((error) => {
console.log(error)
})
}
}
export function loadContacts(contacts) {
return {
type: 'LOAD_CONTACTS',
contacts
}
}
Reducer:
function contacts(state = {}, action) {
switch (action.type) {
case 'ADD_CONTACT':
return "....";
case 'LOAD_CONTACTS':
return action.contacts;
default:
return state
}
}
console log:
contactsBook:
{Book1: Array(3)}
Book1: Array(3)
0: {name: "Bob"}
1: {name: "Jane"}
2: {name: "Mary"}
length: 3
__proto__: Array(0)
__proto__: Object
contacts:
(3) [{…}, {…}, {…}]
0: {name: "Bob"}
1: {name: "Jane"}
2: {name: "Mary"}
length: 3
or
if I use: 
 contacts = Object.values(contactsBook),
there is no output.
console log:
[Array(3)]
0: Array(3)
0: {name: "Bob"}
1: {name: "Jane"}
2: {name: "Mary"}
length: 3
__proto__: Array(0)
length: 1
when using JSON.stringy(contacts),
it prints:
[[ {name: "Bob"}
,..]] rather than [{name: "Bob"},..
 ]
In this case, How to get rid of the outer []?
if mocking up a data warper =[[data]], I can remove the outer layer by warper[0].
but it doesn't work for
contacts = Object.values(contactsBook)
contacts[0]
finally flat() solved this problem
contacts = Object.values(contactsBook).flat()
Could you please help explain the reason?
If I had to guess, you need to add initial state to your reducer that isn't an empty object, like an empty array []. This way when the component first renders and is connected to redux, it'll have a defined value that is valid to map over.
edit
Ok, so your state shape was {[book: string]: string[]}. In this case the initial state ({}) for the reducer was fine and you do need to grab the book name from the route params. Here I've updated the mapStateToProps function to also pull in the component's own props and do the computation to return the contactList as a prop to the component.
/edit
Reducer
const initialState = {};
function contacts(state = initialState, action) {
switch (action.type) {
case 'ADD_CONTACT':
return "....";
case 'LOAD_CONTACTS':
return action.contacts;
default:
return state
}
}
Component
const { contactList } = this.props;
...
contactList.map(...
...
function mapStateToProps(state, ownProps) {
const { match: { params: { bookName } } = ownProps;
return {
contactList: state.contacts[bookName] || [],
}
}
Alternative Solution Guard Pattern
{
contacts && contacts.map(
(contact, index) => (
<tr key={index}>
<td>{contact.name}</td>
<td>{contact.phoneNumber}</td>
</tr>
))
}
Change your map function to this:
{contacts["Book1"].map((contact, index) => (
<tr key={index}>
<td>{contact.name}</td>
<td>{contact.phoneNumber}</td>
</tr>
))}
Code Sandbox: https://codesandbox.io/s/react-example-pevdn

Redux Action Dispatches but does not map to state

I have An action That I am trying to use in my component, My FetchPosts() function will work and map to state, but when I use my other Action FetchUserPosts() I can see in the redux dev tools that the action dispatches, but in State nothing is there and the state doesn't change at all.
It could be something with my action but im not sure.
postAction.js
import { FETCH_POSTS, NEW_POSTS, FETCH_POST_FOR_APPROVAL,
FETCH_POSTS_FROM_USER } from './types';
export const fetchPostsFromUser = (id) => dispatch => {
Promise.all([fetch('http://10.6.254.22:5000/posts/1' + id)])
.then(([res1]) => {
return Promise.all([res1.json()])
})
.then(([posts]) => dispatch ({
type: FETCH_POSTS_FROM_USER,
payload: posts
}));
}
Types.js
export const FETCH_POSTS_FROM_USER = 'FETCH_POSTS_FROM_USER';
PostReducer.js
import { FETCH_POSTS, NEW_POSTS, FETCH_POST_FOR_APPROVAL,
FETCH_POSTS_FROM_USER } from '../actions/types';
const initialState = {
items: [],
item: {}
}
export default function (state = initialState, action ){
switch(action.type) {
case FETCH_POSTS:
console.log('currently reducing')
return{
...state,
items: action.payload
}
case NEW_POSTS:
return{
...state,
item: action.payload
}
case FETCH_POST_FOR_APPROVAL:
return{
...state,
items: action.payload
}
case FETCH_POSTS_FROM_USER:
return{
...state,
items: action.payload
}
default:
return state;
}
}
My Component I want the function to work with so i can map the props.
class ProfilePostBody extends Component {
constructor(props){
super(props)
this.state = {
commentBody: null,
postId: null,
giphyUrl: null,
postPicture: null,
userId: null,
userIdto: null,
userIdName: null,
userIdtoName:null,
// postBody: null,
// giphyUrl: null,
// userIdto: null,
// userIdName: null,
// userIdtoName:'Julio',
displayGifPicker: false
}
}
componentDidMount(){
this.props.fetchPostsFromUser();
this.props.fetchPosts();
}
render () {
return (
// <Grid item xl={6}>
<div>
{this.props.posts.map((post, index) =>
<PostBodyTemplate key={index} postId={post.id} onSubmit=
{this.handleSubmit} onChange={e =>
this.handleInputChange(e,post.id,post.userId,post.userIdName)} title=
{post.title} postBody={post.postBody}
giphyUrl = {post.giphyUrl} userWhoPosted={post.userIdName}
commentBody={post.commentBody} userIdtoName={post.userIdtoName}
userIdName={post.userIdName} />
)}
</div>
)
}
}
ProfilePostBody.propTypes = {
fetchPostsFromUser: PropTypes.func.isRequired,
fetchPosts: PropTypes.func.isRequired,
posts: PropTypes.array.isRequired
}
const mapStateToProps = state =>({
posts: state.posts.items
})
export default connect(mapStateToProps, { fetchPosts, fetchPostsFromUser
})
(ProfilePostBody);
fetchPosts will work, but if i comment it out and try just the fetchPostsFromUser() it will not work.

Map function won't work after react state update

Hi everyone,
I have a map function that maps a data array inside one of my state's. The map function works fine on the first load, but when I start 'pushing' data in the array the following error appears:
TypeError: Cannot read property 'map' of undefined
I don't know what to do next since I absolutely don't know what I'm doing wrong here.
My component:
import React, { Component } from 'react';
import { Button, Table, Input, InputGroup, Container } from 'reactstrap';
import { Person } from './components/Person';
import { getFetch, postFetch } from './utilities/ApiCalls';
export default class App extends Component {
state = {
fetchData: null,
success: undefined,
name: undefined,
birthday: undefined
};
async componentDidMount() {
const response = await getFetch('http://127.0.0.1:8000/api/birthday/all');
this.setState({
fetchData: response
});
}
addPerson = async () => {
const { name, birthday, fetchData } = this.state;
const response = await postFetch('http://127.0.0.1:8000/api/birthday/create', {
name: name,
birthday: birthday
});
this.setState({
fetchData: [...fetchData.data, {
id: response.data.id,
naam: response.data.naam,
geboortedatum: response.data.geboortedatum
}]
});
};
render() {
const { fetchData } = this.state;
return (
<Container>
<Table>
<thead>
<tr>
<th>Name</th>
<th>Date</th>
<th>Age</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
{fetchData ? fetchData.data.map((person) => (
<Person key={person.id} name={person.naam} date={person.geboortedatum}/>
)) : <Person name="Loading..." date="0"/>
}
</tbody>
</Table>
<InputGroup>
<Input type="text" onChange={(e) => this.setState({ name: e.target.value })}/>
<Input type="date" onChange={(e) => this.setState({ birthday: e.target.value })}/>
</InputGroup>
<Button onClick={this.addPerson}>Add Person</Button>
</Container>
);
}
}
Any help is appreciated!
Initially, from your render method you hope fetchData is to be an object with data as a key name which would be an array. But your addPerson function changes this.state.fetchData to an array. You can update your setState in addPerson to be
fetchData: { data: [...fetchData.data, { id: res.data.id ... }] }

React render not rendering my data from api

I created a brand new react application using dotnet core's react templated application using dotnet new react. I then tried to mimic what the Fetch Data Component is doing, and I cannot get my dynamic data to render. I've made sure the component is in the routes component, and that my data is being returned from the server in the format I expect. Here is what I have and what the fetch data component has for code.
FetchData.tsx:
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import 'isomorphic-fetch';
interface FetchDataExampleState {
forecasts: WeatherForecast[];
loading: boolean;
}
export class FetchData extends React.Component<RouteComponentProps<{}>, FetchDataExampleState> {
constructor() {
super();
this.state = { forecasts: [], loading: true };
fetch('api/SampleData/WeatherForecasts')
.then(response => response.json() as Promise<WeatherForecast[]>)
.then(data => {
this.setState({ forecasts: data, loading: false });
});
}
public render() {
let contents = this.state.loading
? <p><em>Loading...</em></p>
: FetchData.renderForecastsTable(this.state.forecasts);
return <div>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
{ contents }
</div>;
}
private static renderForecastsTable(forecasts: WeatherForecast[]) {
return <table className='table'>
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
{forecasts.map(forecast =>
<tr key={ forecast.dateFormatted }>
<td>{ forecast.dateFormatted }</td>
<td>{ forecast.temperatureC }</td>
<td>{ forecast.temperatureF }</td>
<td>{ forecast.summary }</td>
</tr>
)}
</tbody>
</table>;
}
}
interface WeatherForecast {
dateFormatted: string;
temperatureC: number;
temperatureF: number;
summary: string;
}
and here is what I have.
Bills.tsx
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
interface BillState {
bills: Bill[],
loading: boolean
}
export class Bills extends React.Component<RouteComponentProps<{}>, BillState>
{
constructor()
{
super();
this.state = { bills: [], loading: true };
fetch("api/SampleData/GetBills")
.then(response => response.json() as Promise<Bill[]>)
.then(data => { this.setState({
bills: data,
loading: false
});
});
}
public render()
{
let contents = this.state.loading
? <p><em>Loading...</em></p>
: Bills.renderBillsToList(this.state.bills);
return <div className="rendered-bills">
<h1>Bills to pay</h1>
{ contents }
</div>
}
public static renderBillsToList(bills: Bill[])
{
return <ul>
{bills.map( (bill, i) => <li key={ i }> { bill.Name } </li>
)}
</ul>;
}
}
interface Bill
{
Name: string;
}
What am I doing wrong in my RenderBillsToTable? I can see the ul and li's rendering, but not my data that I'm certain is being passed.
Apparently the name of the property was 'name' not 'Name'. Looks like this one was a problem between computer and chair.

How do I get my view to update after an item was removed from my store/State in React with Redux

I am new to React and Redux and just getting comfortable with the idea of managing state and React in general. I preface that as I may need the possible solution to be in the context of what I have—essentially so I will better understand it. :)
That being said this is my problem:
I have created a list/form component in React but having trouble with two glaring problems.
While the item gets removed for the database,
it is only reflected in the view upon a refresh
You may have noticed the list # or the ID column doesn't subtract when items are removed from the list.
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.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>
);
}
}
My 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;
This is how I mount the Students and StudentForm
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>
);
}
}
My 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())
);
After deleting the student you are dispatching the action and you are passing the action creator scrubStudent to dispatch. You are passing id of the deleted student in that action creator. Now the way you have defined your action creator is like this
export function scrubStudent(student) {
return {
type: DELETE_STUDENT,
student
};
}
So the returned value of this function will be an object something like this
scrubStudent(5) // returns {type: "DELETE_STUDENT", student: 5}
But in your reducer you are comparing the ids like this
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;
In the above code action.id is undefined. Instead student id is saved in as action.student. So the comparison will return true for all the elements of array. So everytime all the elements will be included in the new state. So try to change your above code like this
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;

Categories

Resources