Why my state is not not defined? - javascript

Below is es5 syntax
function customMsg(state, action) {
state = state || {};
return $.extend({}, state, {
isFetching: false,
didInvalidate: false,
checkStatus: checkStatus(state.checkStatus, action)
});
}
function checkStatus(state, action) {
state = state || {
isFetching: false,
didInvalidate: false,
type: "room"
};
return state;
}
}
Below is es6 syntax
const initialStae = {
isFetching: false,
didInvalidate: false,
checkStatus: checkStatus(state.checkStatus, action)
}
function customMsg(state = initialStae, action) {
return state;
}
function checkStatus(state, action) {
state = state || {
isFetching: false,
didInvalidate: false,
type: "room"
};
return state;
}
Why my line 7 will show "state is not defined" from es6?
customMsgReducer.js:36Uncaught ReferenceError: state is not defined(…)

In ES5, you define state = state || {}; and then accessing state.checkStatus. Hence its working.
function customMsg(state, action) {
state = state || {};
return $.extend({}, state, {
isFetching: false,
didInvalidate: false,
checkStatus: checkStatus(state.checkStatus, action)
});
}
But in ES6, you access state.checkStatus without defining the state which is undefined here. Hence accessing checkStatus of undefined is throwing error.

Related

does not exist on type 'string'.ts(2339)

Im new to typescript, here i have been adding ts to my react project, i'm getting this kind of error: Property 'identifier' does not exist on type 'string'.ts(2339), the code works as it is but when added ts it gives that error, i can solve it like this: currentBroker: "" as any, but then thats not the right way.
any help/suggestion ?
my code:
const initialSelectionState = {
currentBroker: "",
};
export function selectionReducer(
state = initialSelectionState,
action: selectionReducerAction
) {
switch (action.type) {
case ActionType.CHANGE_SITE:
return {
...state,
currentSite: action.payload,
};
case ActionType.CHANGE_CAMERA:
return {
...state,
currentCamera: action.payload,
};
case ActionType.CHANGE_ANALYSER:
return {
...state,
currentAnalyser: action.payload,
};
case ActionType.CHANGE_PLATFORM:
return {
...state,
currentPlatform: action.payload,
};
case ActionType.CHANGE_BROKER:
return {
...state,
currentBroker: action.payload,
};
case ActionType.CLEAR_ANALYSER_DATA:
return {
...state,
currentAnalyser: "",
};
case ActionType.CLEAR_CAMERA_DATA:
return {
...state,
currentCamera: "",
};
case ActionType.CLEAR_PLATFORM_DATA:
return {
...state,
currentPlatform: "",
};
case ActionType.CLEAR_BROKER_DATA:
return {
...state,
currentBroker: "",
};
case ActionType.UPDATE_BROKER:
const ucurrentBroker =
state.currentBroker.identifier == action.payload.identifier
? action.payload
: state.currentBroker;
return { ...state, currentBroker: ucurrentBroker };
}
}
currentBroker is of type string, it's not an object, and typescript tells you that you cannot access properties because it doesn't have them.
If you are using typescript I suggest you to declare interface of your state first:
interface IState {
currentBroker: string;
}
const initialSelectionState: IState = {
currentBroker: "",
};
and of you need your broker to have an identifier property you can modify the state interface as you need:
interface IState {
currentBroker: {
identifier: string;
}
}
const initialSelectionState: IState = {
currentBroker: {
identifier: ""
};
};
With this you should not have the error again (if I understood correctly)
You initialise the "currentBroker" as a string.
const initialSelectionState = {
currentBroker: "",
};
Then later attempt to access the currentBroker as if it's an object with a property identifier
state.currentBroker.identifier == action.payload.identifier
Casting to any will allow the code to run, and most likely just return undefined when trying to get that property.
If all you are trying to do is update a string in a state object, surely no logic is required?
const initialSelectionState = {
currentBroker: "",
};
export function selectionReducer(
state = initialSelectionState,
action: selectionReducerAction
) {
switch (action.type) {
case ActionType.UPDATE_BROKER:
return { ...state, currentBroker: action.payload};
}
}
Since you mentioned the structure of the payload is as follows;
{
identifier: 'b9b6381e-2d42-4953-b747-4b25fd382a04',
name: 'Broker 244',
host: 'localhost',
port: 1783,
site_id: '0-0-0-0'
}
Then your currentBroker should in some way match the structure of this. Alternatively, if there is 'no current broker initially', you should make it undefined. In either case, it definitely shouldn't be an empty string i.e. "" since that is a totally different data type.

JHipster and React: How to call function after calling asynchronous reducer action?

Use Case: I have a react application generated with JHipster. I need to get data from API, map to form contract, and then submit the form.
Problem: JHipster generated reducer code doesn't return a promise, so how do I know when a reducer action is finished? How can I call a function after getting an entity to update state?
Getting Entity and Returning the ICrudGetAction:
export interface IPayload<T> { // redux-action-type.ts (JHipster Code from node_modules)
type: string;
payload: AxiosPromise<T>;
meta?: any;
}
export type IPayloadResult<T> = ((dispatch: any) => IPayload<T> | Promise<IPayload<T>>);
export type ICrudGetAction<T> = (id: string | number) => IPayload<T> | ((dispatch: any) => IPayload<T>);
// Start of my reducer code
export default (state: AdState = initialState, action): AdState => {
switch (action.type) {
case REQUEST(ACTION_TYPES.FETCH_MYENTITY_LIST):
return {
...state,
errorMessage: null,
updateSuccess: false,
loading: true
};
case FAILURE(ACTION_TYPES.FETCH_MYENTITY_LIST):
return {
...state,
loading: false,
updating: false,
updateSuccess: false,
errorMessage: action.payload
};
case SUCCESS(ACTION_TYPES.FETCH_MYENTITY_LIST): {
const links = parseHeaderForLinks(action.payload.headers.link);
return {
...state,
loading: false,
links,
entities: loadMoreDataWhenScrolled(state.entities, action.payload.data, links),
totalItems: parseInt(action.payload.headers['x-total-count'], 10)
};
}
case ACTION_TYPES.RESET:
return {
...initialState
};
default:
return state;
}
};
export const getEntity: ICrudGetAction<IMyEntity> = id => {
const requestUrl = `${apiUrl}/${id}`;
return {
type: ACTION_TYPES.FETCH_ENTITY,
payload: axios.get<IMyEntity>(requestUrl)
};
};
I try to do this and it works but gives me compile errors:
this.props.getEntity(this.props.match.params.id).then((response) => {
// Map to form attributes and call setState
});
I get error message:
TS2339: Property 'then' does not exist on type 'IPayload | ((dispatch: any) => IPayload)'.
Property 'then' does not exist on type 'IPayload'.
This makes sense because we are not returning a promise. but how can I update the code to return a promise such that I don't break all the things that were autogenerated while also keeping the redux store updated?

React setstate return undefined on componentDidMount()

setState user property inside removeListener return undefined when i console.log() it inside component but when i check state in react developer tool user object from firebase it is there with actual value I want
state = {
coinList: {},
fav: [],
currentFavourite: '',
prices: [],
authed: false,
user: null
};
componentDidMount = () => {
this.removeListener = firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({
authed: true,
user
});
} else {
this.setState({
authed: false
});
}
});
this.ref = base.syncState('fav', {
context: this,
state: 'fav',
asArray: true
});}
If your console.log statement is inside the removeListener, I'd suspect that state hasn't been updated by the time console.log is called.
setState is asynchronous, so it's been updated in the background whilst the next statements are being.
You can provide setState with a function or statement that is only called once setState is completed....
this.setState({ user }, this.someFunction())
or simply...
this.setState({ user }, console.log(this.state.user));

Why we use spread operator into redux

I have seen the following code:
export default function productReducer(state = initialState, action) {
switch(action.type) {
case FETCH_PRODUCTS_BEGIN:
return {
...state,
loading: true,
error: null
};
case FETCH_PRODUCTS_SUCCESS:
return {
...state,
loading: false,
items: action.payload.products
};
case FETCH_PRODUCTS_FAILURE:
return {
...state,
loading: false,
error: action.payload.error,
items: []
};
default:
return state;
}
}
But don't understand why do we use ...state every time for each case.
Can't we just write:
return {
loading: false,
error: action.payload.error,
items: action.payload.products
};
Anyone can explain this?
Because commonly you want to keep other keys inside your state...
If your state has:
{
items:['a', 'b', 'c'],
loading: false,
error: null
}
and you only return for example:
case FETCH_PRODUCTS_BEGIN:
return {
// ...state, --> Without this line
loading: true,
error: null
};
Your new state will be
{
loading: true,
error: null
}
And your items will be lost.
Then, returning:
case FETCH_PRODUCTS_BEGIN:
return {
...state,
loading: true,
error: null
};
You are saying
Return a copy of state, but overriding loading and error keys"
This is for creating new copied state object with new or updated values (without this you would need manually specify every state field).
Object.assign can be used as alternative
Redux Docs has really good explanation about using spread operator.

immutable reducer in redux

Is this reducer looks fine? why the author used a let users;, that look unnecessary to me. Isn't that will cause 2 users in FETCH_USER_FULLFILLED case?
const initalState = {
users: [],
loading: false,
error: null,
};
// REDCUER
function usersReducer(state = initalState, action) {
let users;
switch (action.type) {
case 'FETCH_USER_PENDING':
return { ...state, loading: true };
case 'FETCH_USER_FULFILLED':
users = action.payload.data.results;
return { ...state, loading: false, users };
case 'FETCH_USER_REJECTED':
return { ...state, loading: false, error: `${action.payload.message}` };
default:
return state;
}
}
export default usersReducer;
The reducer is fine and it will not cause two users in FETCH_USER_FULLFILLED. However, you are right, there is no need for let users;. So the code will look like
case 'FETCH_USER_FULFILLED':
return { ...state, loading: false, users: action.payload.data.results };
When the reducer first executed, it will take its start state from initalState as it is the default if no param passed. So users will be empty array at the beginning and will be filled on FETCH_USER_FULLFILLED action
Edit users Added to take advantage of property value shorthand feature in ES6

Categories

Resources