React pagination on scroll - reactjs

i have to implement chat system in react i m doing it first time and i m stuck.i have to pass page no to backend api to get new data every time.and i have to pass page no to api on scroll. i m using
[1]: https://www.npmjs.com/package/react-infinite-scroller
i m getting total data count and 9 data array per page from api.scroll upto which total count is available and when user scroll to top is should load more.i have tried lots of module but failed to implement pagination on scroll.using react-infinite-scroll module i m getting page no but its not working as i want.Please suggest me right way of doing it
here is my component code
const mapStateToProps = state => ({
users: state.sidebarUser.users,
total:state.sidebarUser.total,
routing: state.routing,
converSationId: state.getConversationId.data
});
const mapDispatchToProps = dispatch => ({
loadUserList: (page={}) => (dispatch(getSideBarUser(page))),
getConversationId: (userId) =>
dispatch(getConversationId(userId)),
loadUserContent: id => dispatch(UserChatList(id))
});
class SidebarContainer extends Component {
constructor(props) {
super(props);
this.state={
isLoading:false,
sidebar:[],
page:0,
hasMore: true,
}
this.getPosts=this.getPosts.bind(this);
}
componentDidMount() {
const {
location: { search }
} = this.props.routing;
let userId = new URLSearchParams(search).get("id");
this.props.loadUserList({page:1});
this.setState({page:this.state.page+1});
this.props.getConversationId(userId);
}
getPosts(page) {
console.log("pgae---->",page)
console.log("this.props--->",this.props.users)
this.props.loadUserList({page:page});
}
render() {
const { users } = this.props;
const {hasMore,sidebar} =this.state;
return (
<div className="chatting-user-list-section" ref={(ref) => this.scrollParentRef = ref} >
<InfiniteScroll
initialLoad={false}
pageStart={0}
loadMore={this.getPosts.bind(this)}
hasMore={hasMore}
getScrollParent={() => this.scrollParentRef}
threshold={520}
loader={<div className="loader">Loading ...</div>}>
<SidebarComponent users={users} listClicked={this.listClicked} />
</InfiniteScroll>
</div>)
}
}
export const Sidebar = connect(
mapStateToProps,
mapDispatchToProps
)(SidebarContainer)
and here is my Reducer
import { SIDEBAR_USERS_SUCCESS, SIDEBAR_USERS_FAILURE } from './ActionTypes';
const initialState = {
users: [],
total: 0
}
export const sidebarUser = (state = initialState, { type, payload }) => {
switch (type) {
case SIDEBAR_USERS_SUCCESS: {
return { ...state, ...payload };
}
case SIDEBAR_USERS_FAILURE: {
return { ...state, error: payload }
}
default:
return state;
}
};

Related

state and props are undefined

Hi Im fairly new to coding. I am using react redux and created a store, reducers etc. I cant get anything to render to the screen and when I console.log this.props it comes up an empty array. The data Im dealing with is an array of objects I set the initialstate to an array of objects. I connected all the components with connect and mapstateto props function, there is an empty object in the first arguement of the connect and the second arguement is the componenet. When I look at my component tree it looks fine but my state is undefined and cant figure out why? Here is my code. Thank you in advance.
export const FETCH_SMURFS_START ="FETCH__SMURFS_START"
export const FETCH_SMURFS_SUCCESS = "FETCH_SMURFS_SUCCESS"
export const FETCH_SMURFS_FAILURE ="FETCH_SMURFS_FAILURE"
export const ADD_SMURF_START = "ADD_SMURF_START"
export const ADD_SMURF_SUCCESS = "ADD_SMURF_SUCCESS"
export const ADD_SMURF_FAILURE = "ADD_SMURF_FAILURE"
export const getSmurfData = () =>dispatch=>{
dispatch({type:FETCH_SMURFS_START})
console.log(FETCH_SMURFS_START)
axios.get(' http://localhost:3333/smurfs')
.then((res)=>{
console.log(res.data)
dispatch({type:FETCH_SMURFS_SUCCESS, payload:res.datay})
})
.catch((err)=> {
dispatch({type:FETCH_SMURFS_FAILURE, payload:err.message})
})
}
export const putSmurfData = () =>dispatch=>{
dispatch({type:ADD_SMURF_START})
console.log(ADD_SMURF_START)
dispatch({ADD_SMURF_SUCCESS})
axios.put(' http://localhost:3333/smurfs')
.then((res)=>{
dispatch({type:ADD_SMURF_SUCCESS, payload:res.data})
})
.catch((err)=> {
dispatch({type:ADD_SMURF_FAILURE, payload:err.message})
})
}
class SmurfDisplay extends React.Component {
componentDidMount() {
getSmurfData();
}
render() {
return (
<>
<div>
{this.props.newSmurfData.map((smurf, index) => (
<div>
<h4 key={smurf.id}></h4>
<p> {index}</p>
<p>{smurf.description}</p>
<p>{smurf.nickname}</p>
<p>{smurf.name}</p>
<p>{smurf.position}</p>
</div>
))}
</div>
</>
);
}
}
const mapStateToProps = (state) => {
return {
newSmurfData: [
{
error:state.error,
id: state.id,
name: state.name,
position: state.position,
nickname: state.nickname,
description: state.description,
},
],
};
};
export default connect(mapStateToProps, {})(SmurfDisplay);
class Smurf extends React.Component {
render() {
console.log(this.props);
return (
<>
{this.props.smurfData.map(function(smurf,index) {
return(
<div>
<h4 key={index}></h4>
<p>{smurf.description}</p>
<p>{smurf.nickname}</p>
<p>{smurf.name}</p>
<p>{smurf.position}</p>
</div>
)
})}
</>
)
}
}
const mapStateToProps = (state) =>{
return{
smurfData:[{
error:state.error,
id:state.id,
name:state.name,
position:state.position,
nickname:state.nickname,
description:state.description
}]
}
}
export default connect(mapStateToProps,{})(Smurf)
xport const initialState = {
error:"",
isLoading: false,
smurfData : [{
id:"",
name:"",
position:"",
nickname:"",
description:""
}],
error:"",
isAddingSmurf:false,
newSmurfData:[{
id:"",
name:"",
position:"",
nickname:"",
description:""
}],
}
export const reducer = (state = initialState,action) =>{
switch(action.type){
case FETCH_SMURFS_START:
return{
...state,
isLoading:true,
error:""
}
case FETCH_SMURFS_SUCCESS:
return{
...state,
isLoading:false,
smurfData:action.payload
}
case FETCH_SMURFS_FAILURE:
return{
...state,
isLoading:false,
error:"there was an error getting your smurfs"
}
case ADD_SMURF_START:
return{
...state,
isAddingSmurf:false,
error:""
}
case ADD_SMURF_SUCCESS:
return{
...state,
isAddingSmurf:true,
error: "",
newSmurfData:action.payload
}
case ADD_SMURF_FAILURE:
return{
...state,
isAddingSmurf:false,
addingError:"Error"
}
default:
return state
}
}
export default reducer;
when you want to use this.props in your class Component you need to use super(props) inside the constructor:
constructor(props){
super(props)
}

Sorting Data in Reducer Actions

I am trying to create a sort button which when clicked will sort me menu cards alphabetically. My question is how should I have the sort function coded in the Reducer and Actions? I added pseudo-code for sorting in the Reducer as well. When I click the button I am getting "(TypeError): state.slice is not a function".
Edit:
Added my button component and main Container.
Actions:
export const sortMenus = () => {
return dispatch => {
dispatch({ type: "LOADING_MENUS" });
fetch(`/api/menus`)
.then(res => res.json())
.then(responseJSON => {
dispatch({ type: "SORT_MENUS", cards: responseJSON });
});
};
};
Reducer:
export default function MenusReducer(
state = {
cards: [],
loading: false
},
action
) {
switch (action.type) {
case "LOADING_MENUS":
return {
...state
};
case "ADD_MENUS":
return {
...state,
cards: action.cards
};
case "SORT_MENUS":
return state.slice().sort(function(menu1, menu2) {
if (menu1.name < menu2.name) return -1;
if (menu1.name < menu2.name) return 1;
return 0;
});
default:
return state;
}
}
Button Component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { sortMenus } from ".././actions/dataActions";
import Row from "react-bootstrap/Row";
import Container from "react-bootstrap/Container";
class SortButton extends Component {
constructor() {
super();
this.state = { menus: [] };
}
handleMenuSort = e => {
this.props.sortMenus()
};
render() {
return (
<Container>
<Row>
<div>
<button id="sort-button" title="Sort Menus" onClick= {this.handleMenuSort}>Sort Menus</button>
</div>
</Row>
</Container>
)
}
}
const mapStateToProps = state => {
return {
menus: state.menus
}
};
const mapDispatchToProps = dispatch => {
return {
sortMenus: params => dispatch(sortMenus(params)),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(SortButton)
Container:
class MainContainer extends Component {
displayCards = () => {
switch(this.props.path) {
case "menus":
return (this.props.menus.cards.map(card => (
<NavLink style={{ color: "black" }} to={`/menus/${card.id}`} key={card.id}><MenuCard view={this.props.displayObject} info={card} /></NavLink>
)));
default:
return (<div>Empty</div>)
}
};
render() {
return (
<CardColumns>
{this.displayCards()}
</CardColumns>
)
}
}
const mapStateToProps = state => {
return {
menus: state.menus
}
};
const mapDispatchToProps = dispatch => {
return {
displayObject: (id, category, type) => dispatch(displayObject(id, category, type)),
}
};
export default connect(mapStateToProps, mapDispatchToProps)(MainContainer)
Your state is an object, not an array. You likely mean to sort the stored cards array.
state.cards.slice(... instead of state.slice(...
case "SORT_MENUS":
return state.cards.slice().sort(function(menu1, menu2) {
if (menu1.name < menu2.name) return -1;
if (menu1.name < menu2.name) return 1;
return 0;
});
Side note: You may also want to clear/set your loading state upon successful data fetching. ;)
EDIT
You are mapping undefined state within mapStateToProps, then mapping over it in the component. Change mapStateToProps to access the correct defined property.
const mapStateToProps = state => ({
cards: state.cards,
});
Then you can iterate over the new cards prop.
case "menus":
return (this.props.cards.map(card => (
<NavLink
style={{ color: "black" }}
to={`/menus/${card.id}`}
key={card.id}
>
<MenuCard view={this.props.displayObject} info={card} />
</NavLink>
)));
You can simply store the fetched menu in application state.
You can have standalone action say SORT_MENU_BY_ALPHABET.
You can simply dispatch this action on button handler as well as on Ajax success. this dispatch may not have any payload associated.
hope it helps.
in reducer you defined state as object and you're trying to do array operation on it. state.slice().
slice is a function available for arrays. so its throwing error.
you should be doing
state.cards.slice().sort((a,b)=> a-b)

How to dispatch state of texinput onchangetext to reducer using mapDispatchToProps

I want the states of my textinput to be dispatched to the reducer and change the state of of that reducer by the new state. I also want to be able to view these changed states in a new screen (globally) using mapStateToProps. I am roughly new to redux and I have tried everything possible, but I can seem to get it to work.
Is there any way to do that? I researched and found examples but not the way I want to do it.
I clarify my code is just an example so that you understand what I want to do, do not take it as a guide as I do not know if it works that way
Below are the important part of my code:
Process.Js
import { connect } from 'react-redux';
import {
receiverNameChange,
receiverPhoneChange,
totalParcelsChange } from './actions';
class Process extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
totalParcels: 1,
receiverPhone: '',
receiverName: '',
};
}
onChangeTotalParcels(number) {
const totalParcels = parseInt(number);
if (number.length === 0) {
this.setState({ totalParcels: '' });
} else {
this.setState({ totalParcels });
}
this.props.totalParcelsChange(number);
}
onChangeReceiverNumber = (receiverPhone) => {
this.setState({
receiverPhone
});
this.props.receiverPhoneChange(receiverPhone);
}
onChangeReceiverName = (receiverName) => {
this.setState({
receiverName
});
this.props.receiverNameChange(receiverName);
}
render() {
return (
<View style={styles.AndroidSafeArea}>
<InputField
placeholder={"Enter receiver's name"}
onChangeText={this.onChangeReceiverName}
value={this.state.receiverName}
/>
<InputField
keyboardType={'phone-pad'}
onChangeText={this.onChangeReceiverNumber}
value={this.state.receiverPhone.toString()}
/>
<InputField
keyboardType={'phone-pad'}
onChangeText={this.onChangeTotalParcels}
value={this.state.totalParcels.toString()}
/>
</View>
);
}
}
const mapDispatchToProps = (dispatch) => ({
totalParcelsChange: number => {
dispatch(totalParcelsChange(number));
},
receiverNameChange: receiverName => {
dispatch(receiverNameChange(receiverName));
},
receiverPhoneChange: receiverPhone => {
dispatch(receiverPhoneChange(receiverPhone));
},
});
export default connect(null, mapDispatchToProps)(Process);
Receive.js
import { connect } from 'react-redux';
import {
receiverNameChange,
receiverPhoneChange,
totalParcelsChange } from './actions';
class Receive extends Component {
static navigationOptions = {
header: null,
}
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<View style={styles.AndroidSafeArea}>
<Text>{this.props.receiverNameChange}</Text>
<Text>{this.props.receiverPhoneChange}</Text>
<Text>{this.props.totalParcelsChange}</Text>
</View>
);
}
}
export default connect(null, null)(Receive);
Reduce.js
import { GET_TOTAL_PARCELS, GET_RECEIVER_NAME, GET_RECEIVER_PHONE } from './actions/types';
const initialState = {
receiverName: '',
receiverPhone: '',
number: 0,
};
const ProcessReducer = (state = initialState, action) => {
switch (action.type) {
case GET_TOTAL_PARCELS:
return {
...state,
number: action.payload
};
case GET_RECEIVER_PHONE:
return {
...state,
receiverPhone: action.payload
};
case GET_RECEIVER_NAME:
return {
...state,
receiverName: action.payload
};
default:
return state;
}
};
export default ProcessReducer;
Actions
import { GET_RECEIVER_NAME, GET_RECEIVER_PHONE, GET_TOTAL_PARCELS } from './types';
export const receiverNameChange = (receiverName) => {
return {
type: GET_RECEIVER_NAME,
payload: receiverName
};
};
export const receiverPhoneChange = (receiverPhone) => {
return {
type: GET_RECEIVER_PHONE,
payload: receiverPhone
};
};
export const totalParcelsChange = (number) => {
return {
type: GET_TOTAL_PARCELS,
payload: number
};
};
Kindly correct me where necessary.
I in order for your component in Receive.js to access the state from redux, you should have a mapStateToProps, use it like so:
class Receive extends Component {
...
render() {
return (
<View style={styles.AndroidSafeArea}>
<Text>{this.props.receiverName}</Text>
<Text>{this.props.receiverPhone}</Text>
<Text>{this.props.number}</Text>
</View>
);
}
}
}
const mapStateToProps = state => {
return {
receiverName: state.receiverName,
receiverPhone: state.receiverPhone,
number: state.number
}
}
export default connect(mapStateToProps, null)(Receive);
To have a single source of truth in your Process.Js, you should remove the local state in your Process component and replace the values same as we did in Receive component and you can remove setState.
Hope this helps your problem.

lifecycle react , redux, and redux-form apollo-graphql

I have a redux-form component and another container component that load apollo graphql data. Here below just some important parts of code.
FORM COMPONENT:
class Form extends Component {
constructor(props) {
super(props);
setTimeout(function() {
this.executeCode ( 'onChangeInput', { action: 'initForm' , props: this.props, formProps: this.props, formState: this.state });
}.bind(this), 1000);
}
render() {
(...)
}
}
const ComponentWithData = reduxForm({
form: nameForm,
validate,
})(Form);
function mapStateToProps(state, ownProps) {
const log = false;
const statesReturn = { myState: state };
let initialValues;
initialValues = processValues(ownProps, tableCrud, ownProps.data, 'toClient','view' );
statesReturn.initialValues = initialValues ;
return statesReturn;
}
const ComponentWithDataAndState = connect(
mapStateToProps,
null,
)(ComponentWithData);
export default ComponentWithDataAndState;
CONTAINER COMPONENT:
class FormContainer extends Component {
render() {
const { t, ...otherProps} = this.props;
let aElements = [];
let aQlFiltered = {"crud_view_payment":{"table":"payment"}};
const resultCheck = checkLoadCrud (aQlFiltered,this.props);
if (resultCheck.messageError) {
return <MsgError msg={resultCheck.messageError} t={this.props.t} />;
}
if (!resultCheck.globalLoading && !resultCheck.messageError) {
if (this.props['crud_view_'+tableCrud] && this.props['crud_view_'+tableCrud][tableCrud]) {
if (this.props['crud_view_'+tableCrud][tableCrud].deleted) {
aElements.push(<RecordHeadInfo
key="recordhead"
tableCrud={tableCrud}
{...this.props}
data={this.props['crud_view_'+tableCrud][tableCrud]}
/>);
}
}
}
if (!resultCheck.globalLoading && !resultCheck.messageError) {
aElements.push(<Form
crudAction="View"
key="mainform"
id={ this.props.match.params.id }
data={this.props['crud_view_'+tableCrud][tableCrud]}
onSubmit={this.handleSubmit}
containerPropsForm={this.props}
t={this.props.t}
/>);
}
}
return (
<div>
{aElements}
</div>
);
}
}
const withGraphqlandRouter = compose(
graphql(defQls.payment.View, {
name: 'crud_view_payment',
options: props => {
const optionsValues = { variables: {id: props.match.params.id, _qlType: 'View' }};
optionsValues.fetchPolicy = Tables[tableCrud].fetchPolicy ? Tables[tableCrud].fetchPolicy :'network-only';
return optionsValues;
},
}),
)(withRouter(FormContainer));
const mapStateToProps = (state) => {
return {
myState: state,
};
};
const mapDispatchToProps = (dispatch) => {
return bindActionCreators ({ appSubmitStart, appSubmitStop, showConfirm, initialize, dispatch }, dispatch ); // to set this.props.dispatch
};
const withState = connect(
mapStateToProps ,
mapDispatchToProps,
)(withGraphqlandRouter);
const ComponentFull = withState;
export default ComponentFull;
on Form Component I have a setTimeout that execute a code, because I need set disable or hidden field accord to data loaded. I can't do it directly on construct() neither componentDidMount() because if i try to retrieve data from redux: this.props.myState.form ( have no values). it's for that use a timeout, with 1000 is ok, and with 1 milisecond it's ok too, I see this.props.myState.form.myForm.values (with data retrivied from db trough apollo), i prefer 1 milisecond of course because i don't see blink fields that get disabled or dissapears, but i'm not sure that is a good practice, because in a slow computer or slow browser that can produce conflict with the render ?
It's not clear form the lifecycle mixing react, redux, apollo and redux-form; anyone has idea how i can order better my ideas to write better code here?

React/Redux Why does specific component update, when its sibling’s child component updates, though its state doesn’t change

Update
The sidedrawers state is apparently different, but value does not change...
Details:
There is a layout component, which takes in routes from react router as children.
Inside the layout component code, two child components are rendered, Toolbar, and sidedrawer, and a main section that contains this.props.children.
One of the routes renders a component called page. Page renders another component called graphContainer, and passes it a click event, which is applied to the graphContainer’s button that it renders.
How it works is, I grab the first eight graphs and show 4 of them. When the button is clicked, it decides to either show the next 4 or grab the next eight.
This whole thing uses redux. There’s a page state, authentication state, navigation state, and a graph state. The only partial state changing when the button is clicked, is the graphs.
However, both the GraphContainer updates along with the sidedrawer component. As far as I can tell, nothing in the sidedrawer component is changing, so it should not trigger an update.
In the redux page for navigation state, the switch hits the default, which just returns state.
The graph redux portion works just fine, updates accordingly.
My workaround was to implement a dontUpdate prop in the navigation reducer state. And then use shouldComponentUpdate to check that prop, because the shallow check that was done by default, say with pureComponent, was seeing a different state or prop.
tl;dr: Any ideas why the sidedrawer component keeps updating, even though, as far as I can tell, there’s no prop or state change?
Reducers
const graphReducer = (state = initialState, action) => {
...
case SHOW_NEXTFOUR:
console.log('SHOW NEXT FOUR', state);
return {
...state,
ttlShown: action.ttlShown
};
default:
return state;
}
};
const navReducer = (state = initialState, action) => {
...
default:
return {...state, dontUpdate: true};
}
};
Layout Component
class Layout extends Component {
...
handleSideBarOpen = () => {
this.props.onSidebarToggle();
}
render () {
return (
<Aux>
<Toolbar
isAuth={this.props.isAuthenticated}
drawerToggleClicked={this.handleSideBarOpen}
/>
<SideDrawer
open={this.props.sidebarOpen}
closed={this.props.onSidebarToggle}
/>
<main className={classes.Content}>
{this.props.children}
</main>
</Aux>
)
}
}
const mapStateToProps = ({ navigation, auth }) => {
const { sidebarOpen } = navigation;
const { token } = auth;
return {
sidebarOpen,
isAuthenticated: token !== null
};
};
const mapDispatchToProps = {
onSidebarToggle, getNavTree
};
export default connect(
mapStateToProps, mapDispatchToProps
)(Layout);
Sidedrawer Component
class sideDrawer extends Component {
state = {
popupMenuOpen: false
}
shouldComponentUpdate ( nextProps, nextState ) {
if(nextProps.dontUpdate)
return false;
else return true;
}
…
render() {
…
let navitems = [];
if(this.props.navData && !this.props.error) {
navitems = (
<NavigationItems
showClients={this.props.showClientsBtn}
navData={this.props.navData}
curClientid={this.props.curClientid}
curSiteid={this.props.curSiteid}
curDashid={this.props.curDashid}
curPageid={this.props.curPageid}
closeSidebar={this.props.closed}
onPageClick={this.handlePageClick}
onCSDClick={this.handleOpenPopupMenu}
/>
);
} else
navitems = <p>Problem Loading Tree</p>;
return (
<Aux>
<div className={attachedClasses.join(' ')}>
<div className={classes.Logo}>
<div className={classes.CloseWrapper}>
<Chip onClick={this.props.closed} className={classes.CloseChip}>X</Chip>
</div>
<div className={classes.CrumbWrapper}>
<Breadcrumbs
backBtn={this.handleBackClick}
handleCrumbClick={this.handleCrumbClick}
breadcrumbs={this.props.breadcrumbs}
/>
</div>
</div>
<nav>
{navitems}
<Popover
style={{width: "90%"}}
open={this.state.popupMenuOpen}
anchorEl={this.state.anchorEl}
anchorOrigin={{horizontal: 'middle', vertical: 'bottom'}}
targetOrigin={{horizontal: 'middle', vertical: 'top'}}
onRequestClose={this.handleClosePopupMenu}
>
<Menu
style={{width: "87%"}}>
{MIs}
</Menu>
</Popover>
</nav>
</div>
</Aux>
);
}
};
const mapStateToProps = ({ navigation }) => {
const { dontUpdate, clientid, breadcrumbs,currentPage, selectedClient, selectedSite, selectedDash, selectedPage, navigationData, sidebarOpen, navError } = navigation;
...
}
return {
dontUpdate,
clientid,
showClientsBtn,
navData,
curClientid,
curSiteid,
curDashid,
curPageid,
parentPageid,
sidebarOpen,
navError,
breadcrumbs,
currentPage
};
};
const mapDispatchToProps = {
getNavTree,
onPageSelected,
onSwitchCSD,
onPageRoute
};
export default withRouter(connect(
mapStateToProps, mapDispatchToProps
)(sideDrawer));
Page Component
class Page extends Component {
componentWillMount () {
this.props.getCurPage();
}
render () {
let content = null;
if(this.props.location.state && this.props.location.state.currentPage)
content = (<GraphContainer pageid={this.props.location.state.currentPage} />);
return this.props.location.state && this.props.location.state.currentPage ? (
<Aux>
<p>A PAGE!</p>
{content}
</Aux>
) : (<Redirect to="/" />);
}
}
const mapStateToProps = ({pages}) => {
const { clientid, curPage } = pages;
return {
clientid, curPage
};
};
const mapDispatchToProps = {
getSelectedPage, getCurPage
};
export default connect(
mapStateToProps, mapDispatchToProps
)(Page);
Graph Container
class GraphsContainer extends Component {
componentWillReceiveProps(newProps) {
if(this.props.pageid !== newProps.pageid)
this.props.getFirstEight(newProps.pageid);
}
componentDidMount() {
if(this.props.pageid)
this.props.getFirstEight(this.props.pageid);
}
handleNextClick = (event) => {
event.preventDefault();
this.props.getNextEight(this.props.pageid, this.props.lastNum, this.props.ttlShown);
}
render() {
let graphcards = null;
let disableNext = null;
if (this.props.lastNum >= this.props.ttl)
disableNext = true;
if(this.props.graphs && this.props.graphs.length > 0) {
graphcards = ...
}
return (
<div className={classes.Shell}>
{graphcards}
{this.props.lastNum < this.props.ttl ? (
<div className={classes.NavBtns}>
<RaisedButton disabled={disableNext} onClick={this.handleNextClick}>{'V'}</RaisedButton>
</div>
):null}
</div>
);
}
}
const mapStateToProps = ({pageGraphs}) => {
const { graphs, ttl, lastNum, ttlShown } = pageGraphs;
return {
graphs, ttl, lastNum, ttlShown
};
};
const mapDispatchToProps = {
getFirstEight, getNextEight
};
export default connect(
mapStateToProps, mapDispatchToProps
)(GraphsContainer);
Actions
export const getFirstEight = (pageid) => {
let str = ...;
return (dispatch) => {
axios.get( str )
.then( response => {
let data = {};
let graphs;
let ttl;
let newLastNum = 0;
if((typeof response.data !== 'undefined') && (response.data !== null)) {
data = {...response.data};
ttl = data.total;
if(ttl <= 8) {
graphs = [...data.graphs];
newLastNum = ttl;
} else {
graphs = [...data.graphs].slice(0,8);
newLastNum = 8;
}
}
dispatch({type: GET_FIRSTEIGHT, payload: {ttl,graphs, lastNum:newLastNum}});
} )
.catch( error => {
console.log('ERROR FETCHING NAV TREE', error);
dispatch({type: GET_FIRSTEIGHT, payload: {}});
} );
};
};
export const getNextEight = (pageid, lastNum, ttlShown) => {
let str = ...;
let newLastNum = 0;
return (dispatch) => {
if(ttlShown < lastNum) {
dispatch({type: SHOW_NEXTFOUR, ttlShown: ttlShown+4});
} else {
axios.get( str )
.then( response => {
// console.log('[RESPONSE]', response);
let data = {};
let graphs;
let ttl;
if((typeof response.data !== 'undefined') && (response.data !== null)) {
data = {...response.data};
ttl = data.total;
if(ttl <= (lastNum+8)) {
graphs = [...data.graphs].slice(lastNum);
newLastNum = ttl;
} else {
graphs = [...data.graphs].filter((el,index) => {
return (index > (lastNum-1)) && (index < (lastNum+8));
});
newLastNum = lastNum+8;
}
}
dispatch({type: GET_NEXTEIGHT, payload: {ttl,graphs, lastNum:newLastNum, ttlShown: ttlShown+4}});
} )
.catch( error => {
console.log('ERROR FETCHING NAV TREE', error);
dispatch({type: GET_NEXTEIGHT, payload: {}});
} );
}
};
};

Resources