Wait for AJAX request ( React, Redux) - javascript

Need display data after AJAX call will be done.
My Reducer:
import { INCOME_PROFILE } from '../actionTypes'
import Immutable from 'immutable'
const initialUserState = [];
const profileReducer = function(state = initialUserState, action) {
//console.log('actiondata in reducer:' + action.data + action.type);
switch(action.type) {
case 'INCOME_PROFILE_IS_LOADING':
return Object.assign({}, state, { hh: action.hasFetched });
case 'INCOME_PROFILE':
return Object.assign({}, state, { course_list: action.data, hh: action.hasFetched });
default:
return state;
}
}
export default profileReducer
My action creator:
export function GET_ITEM_REQUEST() {
return {
type: INCOME_PROFILE_IS_LOADING,
hasFetched: false,
}
}
function receiveData(json) {
return{
type: INCOME_PROFILE,
data: json,
hasFetched: true
}
};
export function IncomeProfileList () {
return dispatch => {
return (
axios.post(Api.getURI("profile"),{}, {
headers: { 'X-Authenticated-Userid': '15000500000#1' }
}).then(function (response) {
//console.log(response.data);
dispatch(receiveData(response.data.body));
})
.catch((error) => {
console.log(error);
})
)
}
}
My component:
class IncomeProfile extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
this.props.IncomeListProfile();
}
render() {
console.log(this.props.isloading);
if (this.props.isloading) {
return <p>Sorry! There was an error loading the items</p>;
}
}
}
const mapDispatchToProps = function(dispatch) {
return {
IncomeListProfile: () => dispatch(IncomeProfileList())
}
}
const mapStateToProps = function(state) {
//var mystore = state.toJS()
var mystore = state.getIn(['incomeProfileList'])['course_list'];
var mystored = state.getIn(['incomeProfileList']);
console.log(mystored.hh);
var copy = Object.assign({}, mystore);
return {
items: copy.course_list,
isloading: mystored.hh
};
}
I need next: While response not finish, I no need to display data. Condition if not works now
console.log at first time get undefined - think must be false, but it not state false. and second time it's getting true.

You don't need property 'isLoading' - just handle 2 cases in which you have your data and you haven't. Put this condition in render() function, because the component is going to refresh after passing data through the reducer. Syntax will be something like this in your case:
render() {
if(!this.props.items) {
return <div>Loading...</div>;
} else {
return (
<div>Display your data!</div>
);
}
}

Related

react-dom.development.js:20312 Uncaught TypeError: main.get is not a function - React Redux Sagas- rendering mock json data on UI

I am trying to display a mock JSON data using react-sagas to display the dummy data on my my main component. I followed all the steps related related to setting up the sagas and store. but my main components doesn't show any data in return I keep getting an error pointing which points to my selectors. Uncaught TypeError: main.get is not a function
1. Main Component
class Main extends React.Component {
static propTypes = {
handlePOConfigRules: PropTypes.func,
rules: PropTypes.object
};
constructor(props, context) {
super(props, context);
this.state = {
priorityCardList: [
{
title: "Rule Priority 1 ",
id: "1",
rule_code: "NW"
},
{
title: "Rule Priority 2",
id: "2",
rule_code: "3D"
},
]
};
this.props.handlePOConfigRules();
}
componentDidMount() {
console.log("1. Mount - Props", this.props);
console.log("2. Mount - State", this.state);
}
render() {
const { priorityCardList } = this.state;
const { rules } = this.props;
console.log("Main render props --", rules);
return (
<>
{/* Loop through the cardlist for rule priority */}
{priorityCardList.map(element =>
<RuleDetailCard title={element.title}
id={element.id}
rule_code={element.rule_code} />
)}
</>
)
}
}
const mapDispatchToProps = (dispatch) => {
return {
// dispatching plain actions
handlePOConfigRules: () => dispatch(actions.getRuleDetails())
}
}
const mapStatetoProps = () => createStructuredSelector({
rules: selectors.getRuleDetails()
});
export default connect(mapStatetoProps, mapDispatchToProps)(Main);
2. Actions :
export function getRuleDetails(){
return {
type: 'GET_PO_CONFIG_START'
}
}
export function getRuleDetailsSuccess({rules}){
return {
type: 'GET_PO_CONFIG_SUCCESS',
payload: {rules}
}
}
3. Reducer :
export const initialState = fromJS({
//inital setup of reducers
rules: []
});
function main(state = initialState, action) {
switch (action.type) {
case 'GET_PO_CONFIG_START':
return { ...state, rules: initialState.rules};
case 'GET_PO_CONFIG_SUCCESS':
return { ...state, rules: action.payload}
case 'GET_PO_CONFIG_ERROR':
return { ...state, rules: initialState.rules}
default:
return state
}
}
export default main;
4. Selectors
import { createSelector } from 'reselect';
const mainState = (state) => state?.['main'];
export const getRuleDetails = () => createSelector(
mainState,
(main) =>{
const data = main.get('rules') ? main.get('rules').toJS(): [];
return data;
}
);
5. Sagas
export function* getPOConfigData(action) {
try {
const { payload } = action;
// Api Call from services
const results = yield call(getAllPOConfigs, payload);
//Selectors
const ruleList = yield select(selectors.getRuleDetails());
//On success set the payload value
yield put(actions.getRuleDetailsSuccess({rules: results}));
} catch (e) {
yield put({ type: 'GET_PO_CONFIG_ERROR', message: e.message });
}
}
export function* POConfigWatcher() {
//debugger;
yield takeLatest('GET_PO_CONFIG_START', getPOConfigData);
}
export default [
fork(POConfigWatcher)
]
In selectors, const data = main.get('rules') ? main.get('rules').toJS(): []; is where i am getting error while accessing this.props.rules in my Main component. Can anyone guide me what is missing here ???

Get the EditorState(DraftJS) from DB with Redux

I want to repopulate the editor's state with the values i have saved to Firebase.
OnSubmit:
sendNotes = (e) => {
e.preventDefault();
let contentState = this.state.editorState.getCurrentContent()
let note = { content: convertToRaw(contentState) }
note["content"] = JSON.stringify(note.content);
this.props.createNote(note.content);
};
NoteAction:
export function getNote() {
return (dispatch) => {
database.on("value", (snapshot) => {
dispatch({
type: LOAD_NOTE,
payload: snapshot.val(),
});
});
};
}
noteReducer:
export default function (state = {}, action) {
switch (action.type) {
case LOAD_NOTE:
return action.payload;
default:
return state;
}
}
REDUX/firebase:
{
type: 'LOAD_NOTE',
payload: {
'-MNOwBIWNqY_ZFDO4ILs': '{"blocks":[{"key":"c27el","text":"ASD!!!!!!!!!!!!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyHLvaORxEmuuJmzJ': '{"blocks":[{"key":"c27el","text":"HELLO WORLD","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyP50oGHRLiP3T5_h': '{"blocks":[{"key":"c27el","text":"This is a REDUX STORE","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}'
}
}
MapStateToProps:
function mapStateToProps(state, ownProps) {
return {
note: state.notes,
};
}
export default connect(mapStateToProps, { getNote })(TextEditor);
My Code:
componentDidMount() {
this.props.getNote();
}
componentWillReceiveProps = (nextProps) => {
if (nextProps.note !== null) {
let item = "";
_.map(nextProps.note, (note, key) => {
return (item = note);
});
this.setState({
editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(item))),
});
}
};
The code is working but I'm not 100% sure about these lifecycle methods & if the code i have written is 'stable'. I am stuck with this, please :).

Trying to populate props with async promise inside of ComponentDidMount

So inside of my uncontrolled PossibleMatches component, I know from the way React works, the initial rendering phase will occur with empty prop values (if those prop values rely on external application state (mapStateToProps)) regardless of whether or not I have a componentDidMount lifecycle method or constructor setup. In response to this, I've setup a promise inside of the componentDidMount so that when I dispatch prop functions [defaultPieces, arrangePieces], I can have the UI render an ActivityIndicator to indicate something is currently fetching. The problem is, I cannot seem to get the mapStateToProps function to understand the state when I call mapStateToProps from within the success phase of the promise. Here it is:
class PossibleMatches extends Component {
constructor(props){
super(props);
}
componentDidMount(props){
return new Promise((resolve, reject) => {
let state;
let {defaultPieces, arrangePieces, isFetching} = this.props;
let makeClothesAppear = function(){
defaultPieces();
arrangePieces();
isFetching = true;
}
resolve(makeClothesAppear());
}).then(function(state){
mapStateToProps(state);
this.props.isFetched = true
this.props.isFetching = false;
}).catch((error) => {
console.log('FetchClothesError: ', error);
})
}
}
How the UI would make a decision on what to display:
renderDecision(){
const {UpperComponents, LowerComponents} = this.props;
const {currentUpperComponent, currentLowerComponent} = this.state.currentComponent.whichPiece;
const {LowerComponentEnabled, UpperComponentEnabled} = this.state;
if (this.props.isFetching){
return (<div className='activityLoader'>
<ActivityIndicator number={3} duration={200} activeColor="#fff" borderWidth={2} borderColor="50%" diameter={20}/>
</div>);
} else if (this.props.isFetched){
return (<div className = "PossibleMatches_Container">
<i className = 'captureOutfit' onClick = {this.snapshotMatch}></i>
{UpperComponents.map((component) => {
return (<UpperComponent key={component.createdAt} id={component.id}
switchComponent={this.switchFocus}
setCurrentPiece = {this.setNewPiece}
evaluatePiece={this.isOppositeComponentSuggested}
image={component.image}
toggleToPiece = {(LowerComponentEnabled) => {if (LowerComponentEnabled === false){this.setState({LowerComponentEnabled: true})}else{return;} this.setState({currentLowerComponent: this.props.suggestedBottoms[0]})}}
isLowerComponentEnabled={LowerComponentEnabled}
ref={this.residingUpperComponent}
className = {this.state.currentComponent.whichPiece.whichType === 'match' ? 'PossibleMatches_Container' : this.state.currentComponent.whichPiece.whichType === 'bottom' ? 'standalonePiece' : 'standalonePiece'}/>)
})
}
{LowerComponents.map((component) => {
return (<LowerComponent key={component.createdAt} id={component.id}
setCurrentPiece = {this.setNewPiece}
evaluatePiece={this.isOppositeComponentSuggested}
image={component.image}
toggleToPiece={(UpperComponentEnabled) => {if (UpperComponentEnabled === false){this.setState({UpperComponentEnabled: true})}else{return;} this.setState({currentUpperComponent: this.props.suggestedTops[0]})}}
switchComponent={this.switchFocus}
isUpperComponentEnabled={UpperComponentEnabled}
ref={this.residingLowerComponent}
className = {this.state.currentComponent.whichPiece.whichType === 'match' ? 'PossibleMatches_Container' : this.state.currentComponent.whichPiece.whichType === 'bottom' ? 'standalonePiece' : 'standalonePiece'}/>)
})
}
</div>)
}
}
render(){
return(
<div className = 'GorClothingContainer'>
{/*<Wardrobe upperComponent={this.state.currentComponent.whichPiece.currentUpperComponent} lowerComponent={this.state.currentComponent.whichPiece.currentLowerComponent} enableCapture={(snapshot) => this.snapshotMatch = snapshot} />*/}
{this.renderDecision()}
</div>
);
}
My PossibleMatches Reducer
import {INITIAL_PIECES, GET_ANCILLARY_PIECES, ORGANIZE_PIECES, SET_CONTEMPLATED_PIECE} from '../actions/types';
const initialState = {
UpperComponents: [],
LowerComponents: [],
contemplated_piece: null,
extraTops: [],
extraBottoms: [],
standaloneTops: [],
standaloneBottoms: [],
suggestedTops: [],
suggestedBottoms: []
}
export default function(state = initialState, action){
switch(action.type){
case INITIAL_PIECES:
return Object.assign({}, state, {contemplated_piece: action.payload.contemplated_piece},
{extraTops: action.payload.extra_tops},
{extraBottoms: action.payload.extra_bottoms},
{standaloneTops: action.payload.standalone_tops},
{standaloneBottoms: action.payload.standalone_bottoms},
{suggestedTops: action.payload.suggested_tops},
{suggestedBottoms: action.payload.suggested_bottoms})
case GET_ANCILLARY_PIECES:
return Object.assign({}, state, {extraTops: action.payload.extra_tops},
{extraBottoms: action.payload.extra_bottoms},
{standaloneTops: action.payload.standalone_tops},
{standaloneBottoms: action.payload.standalone_bottoms},
{suggestedTops: action.payload.suggested_tops},
{suggestedBottoms: action.payload.suggested_bottoms})
case ORGANIZE_PIECES:
return Object.assign({}, state, {UpperComponents: action.payload.UpperComponents},
{LowerComponents: action.payload.LowerComponents})
case SET_CONTEMPLATED_PIECE:
return Object.assign({}, state, {contemplated_piece: action.payload.contemplated_piece})
default:
return state;
}
}
My combineReducers segment
import {combineReducers} from 'redux';
const allReducers = combineReducers({
Playlist: PlaylistReducer,
eventOptions: eventTicketReducer,
possibleMatches: PossibleMatchesReducer,
Intro: combineForms({
basicUserInfo: BasicUserInfoState,
GenderInfo: GenderInfoState,
ContactInfo: ContactInfoState
}, 'Intro'),
routing: routerReducer,
form: formReducer
});
Prop Values:
PossibleMatches.defaultProps = {
isFetching: true,
isFetched: false
}
My mapStateToProps function
function mapStateToProps(state){
return {UpperComponents: state.possibleMatches.UpperComponents,
LowerComponents: state.possibleMatches.LowerComponents,
contemplatedPiece: state.possibleMatches.contemplated_piece,
extraTops: state.possibleMatches.extraTops,
extraBottoms: state.possibleMatches.extraBottoms,
standaloneTops: state.possibleMatches.standaloneTops,
standaloneBottoms: state.possibleMatches.standaloneBottoms,
suggestedTops: state.possibleMatches.suggestedTops,
suggestedBottoms: state.possibleMatches.suggestedBottoms}
}
function mapDispatchToProps(dispatch){
return {
defaultPieces: () => {
dispatch(defaultPieces())
},
arrangePieces: () => {
dispatch(arrangePieces())
},
getCorrespondingPieces: () => {
dispatch(getCorrespondingPieces())
},
setEvaluatedPiece: () => {
dispatch(setEvaluatedPiece())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PossibleMatches)
My Question is: What exactly is wrong with the way that I've implemented the promise. With the reducers and the redux actions setup correctly(I know because I've logged the fetched items to the console from the redux actions file), how can I properly populate the prop values in mapStateToProps. Currently the error is:
Im using React 16.4.0
A simple redux use case would seem as follows
possibleMatches.jsx (Component file)
class PossibleMatches extends React.Component {
state = {
isFetching: false
}
componentDidMount() {
this.setState({isFetching: true})
fetchingSomethingFromServer()
.then(resp => {
this.setState({isFetching: false})
this.props.UpdateRedux(resp)
});
}
render() {
const { isFetching } = this.state;
const { data } = this.props;
return (
isFetching ? <div>loading...</div> : <div>{data}</div>
)
}
}
export default connect(state => ({ data: state.possibleMatches.data }), {UpdateRedux})
actions.js (action creator file)
Use this action to update any data into redux
export const UpdateRedux = (data) => {type: 'UPDATE_REDUX', payload: data}
reducers.js
This is the file that holds the redux state
const defaultState = {
data: null
}
export default (state = defaultState, action) => {
switch(action.type) {
case 'UPDATE_REDUX':
return {data: action.payload};
default:
return state
}
}
In your combine reducers import this reducer and assign it as follows
import possibleMatches from 'reducers.js';
combineReducers({ possibleMatches });

Redux dispatches an API call failure even though the network tab in devtools shows the API call received a status of 200

I am new to redux and I am having a hard time understanding how to connect the payload of my API call to my state.
Right now my action.js file looks like this:
import ApiService from '../../services/ApiService';
import { reset } from 'redux-form';
//actions
export const getStock = () => {
return {
type: 'GET_STOCK'
}
}
export const getStockPending = () => {
return {
type: 'GET_STOCK_PENDING'
}
}
export const getStockFulfilled = (stock) => {
return {
type: 'GET_STOCK_FULFILLED',
payload: stock
}
}
export const getStockRejected = () => {
return {
type: 'GET_STOCK_REJECTED'
}
}
// async function calls
export function fetchStocksWithRedux() {
const action_type = "GET_STOCK";
const stock = 'AAPL';
return (dispatch) => {
dispatch({type: `${action_type}_PENDING`});
return ApiService.get(`/search?query=${stock}`)
.then(([response, json]) =>{
if(response.status === 200){
dispatch(getStockFulfilled(json))
}
else{
dispatch(getStockRejected())
}
})
}
}
and my reducer.js file looks like this:
const initialState = {
inProgress: false,
stock: {},
stocks: ['NKE', 'AMZN', 'AAPL'],
error: {}
}
export default (state = initialState, action) => {
switch(action.type) {
case 'GET_STOCK_PENDING':
return {
...state,
inProgress: true,
error: false
}
case 'GET_STOCK_FULFILLED':
return {
...state,
stock: action.payload,
inProgress: false
}
case 'GET_STOCK_REJECTED':
return {
...state,
inProgress: false,
error: action.error
}
default:
return state;
}
}
When I go to call my method fetchStocksWithRedux in my component, the network tab in my dev tools shows a 200 status and the response I'm expecting, but the reducer dispatches the 'GET_STOCK_REJECTED' action, but the error hash is empty. What do you think is going wrong?
Here is my component, for reference:
import React, { Component } from 'react';
import { fetchStocksWithRedux } from '../../redux/modules/Stock/actions';
import { connect } from 'react-redux';
class Dashboard extends Component {
componentDidMount() {
this.props.fetchStocksWithRedux()
}
render() {
return (
<div className="uk-position-center">
</div>
)
}
}
export default connect(
state => ({
stocks: state.stocks,
stock: state.stock
})
, { fetchStocksWithRedux }
)(Dashboard);
Thanks. Any advice or guidance would be greatly appreciated!

Redux connected React component not updating on state change

Whenever my 'COLLEGE_ADDED' action is dispatched I can see the state changes in the reducer. However the update related lifecycle methods on the CollegeSearchList component and it's children aren't being called. These components aren't re-rendering presumably because of this.
I have read the docs about not mutating state and I don't think I am. Complete code can be found here https://github.com/tlatkinson/react-search-widget.
components/search/college/CollegeSearchList.js
class CollegeSearchList extends Component {
componentWillUpdate (nextProps, nextState) {
console.log(nextProps.searchItems);
console.log(nextState);
return true;
}
render () {
return (
<SearchList searchItems={this.props.searchItems} SearchListItem={CollegeSearchListItem} />
)
}
}
const mapStateToProps = (state, {id}) => {
return {
searchItems: getSearchResultsById(state.searchState, id),
SearchListItem: CollegeSearchListItem,
}
};
CollegeSearchList = connect(
mapStateToProps
)(CollegeSearchList);
reducers/search.js
const searchReducer = (searchState = [], action) => {
switch(action.type) {
case 'COLLEGE_SEARCH':
return mergeData(searchState, action, 'college', 'phrase');
case 'COLLEGE_SEARCH_SUCCESS':
return mergeData(searchState, action, 'college', 'searchResults');
case 'COLLEGE_ADDED':
return updateCollegeAdded(searchState, action.collegeId, true);
case 'COLLEGE_REMOVED':
return updateCollegeAdded(searchState, action.collegeId, false);
default:
return searchState;
}
};
export default searchReducer
const updateCollegeAdded = (searchState, collegeId, added) => {
const newState = {...searchState};
for (let id of Object.keys(newState)) {
const searchComponent = searchState[id];
if(searchComponent.searchType === 'college') {
searchComponent.searchResults.forEach(searchResult => {
if(searchResult.id === collegeId) {
searchResult.added = added;
}
});
}
}
return newState;
};
const mergeData = (data, action, searchType, propertyModified) => {
return {
...data,
[action.id]: {
searchType,
...data[action.id],
[propertyModified]: action[propertyModified],
}
};
};
actions/index.js
export const addRemoveCollege = (collegeId, collegeName, addToList) => (dispatch) => {
if (addToList) {
api.addToCollegeList(collegeId)
.then(() => {
dispatch({
type: 'COLLEGE_ADDED',
collegeId,
collegeName,
});
})
} else {
api.removeFromCollegeList(collegeId)
.then(() => {
dispatch({
type: 'COLLEGE_REMOVED',
collegeId,
collegeName,
});
})
}
};

Categories

Resources