css not updating after re-redering component in redux react - javascript

I am trying to create a webpage using React.
used redux for data access.
My problem is that when I click on any product, it shows me a perfect page, but if I go back and then again click on another product, my page shows me the data of the new product, but it does not change the photo height in CSS.
home page
product 1product 2(its doesnt changing first image height)
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return {
loading: true,
...state <------i am sending the previous state
}
case PRODUCT_DETAILS_SUCCESS:
return {
loading: false,
product: action.payload,
}
case PRODUCT_DETAILS_FAIL:
return {
loading: false,
error: action.payload
}
case CLEAR_ERRORS:
return {
...state,
error: null
}
default:
return state
}

You must first iterate, and then provide the changes.
return {
...state <------ iterate
loading: true, <----- set new values
}
In addition, you should always iterate, just to make sure, you're not changing the whole state.
export const productDetailsReducer = (state = { product: {} }, action) => {
switch (action.type) {
case PRODUCT_DETAILS_REQUEST:
return {
...state
loading: true,
}
case PRODUCT_DETAILS_SUCCESS:
return {
...state,
loading: false,
product: action.payload,
}
case PRODUCT_DETAILS_FAIL:
return {
...state,
loading: false,
error: action.payload
}
case CLEAR_ERRORS:
return {
...state,
error: null
}
default:
return state
}

Related

Pervious state is removed when I update state in react native redux

I call get_user_profile_api inside the app after login. On successful login my appĀ has user and token in the state. But as soon as GET_USER_PROFILE_SUCCESS is called, the state is left only with userData and isLoading. user and token are removed from the state.
import { CONST } from '../../utils/Const';
import * as types from './types';
const initialState = {
isLoading: false,
user: null,
userData: null,
isLoggedIn: false,
token: '',
};
export default authReducer = (state = initialState, action) => {
console.log('action :: ', action);
switch (action.type) {
case types.GET_USER_PROFILE_LOADING:
case types.LOGIN_LOADING:
return {
isLoading: true,
};
case types.GET_USER_PROFILE_SUCCESS:
return {
...state,
isLoading: false,
userData: action.payload,
};
case types.LOGIN_SUCCESS:
return {
...state,
isLoading: false,
isLoggedIn: true,
user: action.payload.user,
token: action.payload.token,
};
case types.LOGIN_ERROR:
case types.GET_USER_PROFILE_ERROR:
return {
...state,
isLoading: false,
};
default:
return {
...state,
isLoading: false,
};
}
};
there is nothing wrong with this code I think the issue is where you are calling these actions from and you can call them inside a use-effect hook to get a user profile if there is a token or maybe you are not mapping state to props correctly
I was not writing ...state in the LOADING case. That's why my state was being removed.

Redux: altering different parts of the initial state in Reducer according to Actions

I have the following Reducer:
const initialState = {}
const dishReducer = (state = initialState, action) => {
switch (action.type) {
case 'LOAD_DISHES':
return (action.dishes)
case 'LOAD_DISHES_ERROR':
console.log("load dishes error")
return state
case 'LOAD_DISHES_SUCCESS':
console.log("load dishes success")
return state
default:
return state;
}
};
export default dishReducer;
And the following action(s):
import {database} from '../../config/fbConfig'
export const startLoadingDishes = (dishes) => {
return (dispatch) =>{
return database.ref('products-dishes').once('value').then((snapshot) => {
let dishes = {}
snapshot.forEach((childSnapshot) => {
let parentkey = childSnapshot.key
let dishArray = [];
childSnapshot.forEach((dish) =>{
dishArray.push(dish.val())
});
dishes[childSnapshot.key] = dishArray;
})
dispatch(loadDishes(dishes))
}).then(() => {
dispatch({ type: 'LOAD_DISHES_SUCCESS' });
}).catch(err => {
dispatch({ type: 'LOAD_DISHES_ERROR' }, err);
});
}
}
export const loadDishes = (dishes) => {
return {
type: 'LOAD_DISHES',
dishes
}
}
The 'startLoadingDishes' action is called inside the componentDidLoad() of a certain Component. However, I want to alter the initial state of my dishReducer so that it includes additional information, as follows:
const initialState = {
value : {},
loaded: false,
loading: false,
error: false
}
So now 'action.dishes' returned by reducer [in 'LOAD_DISHES' case] should be put inside the 'value' part of the state, instead of it being the whole state. Also, the 'loaded' part of the state should be set to true if dishes have already been loaded earlier, and so on. I understand this is fairly simple but as I am new to React+Redux, I don't know how to alter the Action/Reducer codes properly (while keeping state immutability). Any help is appreciated.
I originally asked the question, here is how I solved it (not sure if this is the 'best' way though):
New reducer file:
const initialState = {
value : {},
loaded: false,
loading: false,
error: false
}
const dishReducer = (state = initialState, action) => {
switch (action.type) {
case 'LOAD_DISHES':
return {
value: action.dishes,
loading: !state.loading,
loaded: false, //this might need to be set to true
error: false
}
case 'LOAD_DISHES_ERROR':
console.log("load dishes error")
return {
...state, //or: state.value, as the other parts of state are being overwritten below
loaded: false,
loading: false,
error: true
}
case 'LOAD_DISHES_SUCCESS':
console.log("load dishes success")
return {
...state, //better: state.value
loaded: true,
loading: false,
error: false
}
default:
return state;
}
};
export default dishReducer;
No change in actions file.
Now, inside the 'Main' component, I was originally accessing the state as such:
class Main extends Component {
componentDidMount() {
this.props.startLoadingDishes();
}
render() {
return (
//some code
)
}
}
const mapStateToProps = (state) => {
return {
dishes: state.dishes //to access dishes: dishes.value
}
}
export default connect(mapStateToProps, actions)(Main)
The Main component code also stayed the same, with the difference that now I use 'dishes.value' instead of just 'dishes' to access the value of dishes from the state (and dishes.loaded for loaded, and so on). And now the action caller inside componentDidMount is as follows:
componentDidMount() {
if(!this.props.dishes.loaded){
this.props.startLoadingDishes();
console.log("loading dishes from database")
}
}

TypeError: state is not iterable on react and redux

So i just learned redux and tried to make a simple list with redux and react.
but when i click on the button to add item to the list i got an error "state is not iterable"
here is my code
reducer
function manageList(state = { items: [] }, action) {
switch (action.type) {
case ADD_ITEM:
return { list: [...state, action.payload] };
case RESET_LIST:
return {
item: [...state, []],
};
default:
return state;
}
}
action
export const ADD_ITEM = "ADD_ITEM";
export const RESET_LIST = "RESET_LIST";
export function addItem(text) {
return { type: ADD_ITEM, payload: text };
}
export function resetList() {
return { type: RESET_LIST };
}
You're spreading an object inside an array, to fix that you should spread the items property inside an array:
function manageList(state = { items: [] }, action) {
switch (action.type) {
case ADD_ITEM:
return { list: [...state.items, action.payload] };
case RESET_LIST:
return {
items: [...state.items, []],
};
default:
return state;
}
}
I think also that you should replace list and item by items :
function manageList(state = { items: [] }, action) {
switch (action.type) {
case ADD_ITEM:
return { items: [...state.items, action.payload] };
case RESET_LIST:
return {
items: [...state.items, []],
};
default:
return state;
}
}
I think you should spread them as "state.items" not as just "state".
Like this:
item: [...state.items,[]]
Not like this:
item: [...state,[]]
export const commentReducer = (state = initialState, action) => {
switch (action.type) {
case COMMENT_REQUEST:
return {
...state,
loading: true,
};
case COMMENT_SUCCESS:
return {
...state,
comment: [...state.comment, action.payload],
};
case COMMENT_FAIL:
return { loading: false, error: action.payload };
default:
return state;
}
};
It works for me

Can't display data from my state/props in react-redux

I have a component that displays a single Article object that is fetched from a Mongo database. It goes through my reducer and then I use mapStateToProps to put the state into this.props. I then want to display the data from that object but I cannot figure out how to do so. The page is called ArticleShow (It shows one article.)
ArticleShow.js
class ArticleShow extends Component {
componentDidMount() {
this.props.getArticle(this.props.id);
}
render() {
// I know this is wrong
const articleData = this.props.article;
return (
<Container>
</Container>
);
}
}
ArticleShow.propTypes = {
getArticle: PropTypes.func.isRequired,
article: PropTypes.object.isRequired,
};
const mapStateToProps = (state) => ({
article: state.article.articles,
});
export default connect(mapStateToProps, { getArticle })(ArticleShow);
articleReducer.js
const intialState = {
articles: [],
loading: false,
};
export default function (state = intialState, action) {
switch (action.type) {
case GET_ARTICLE:
return {
...state,
articles: {
[action.payload._id]: action.payload,
},
loading: false,
};
}
Below is the data when I console.log(this.props.article). It contains all the data I want to display but nothing that I do allows me to display the data.
this.props.article
5f0f80157f7feb0a2512130a:
author: "Shempton McGruntie"
body: "orem Ipsum is simply dummy text of the
printing and typesetting industry. Lorem Ipsum has
been "
date: "2020-07-15T22:15:49.787Z"
name: "Article_2"
__v: 0
_id: "5f0f80157f7feb0a2512130a"
__proto__: Object
-- Note: I can change the payload by changing the index from ._id to name, but I have the exact same problem and cannot access any of the data.
articleReducer.js
const intialState = {
articles: [],
loading: false,
};
export default function (state = intialState, action) {
switch (action.type) {
case GET_ARTICLE:
return {
...state,
articles: {
[action.payload.name]: action.payload,
},
loading: false,
};
}
this.props.article
Article_2:
author: "Shempton McGruntie"
body: "orem Ipsum is simply dummy text of the
printing and typesetting industry. Lorem Ipsum has
been "
date: "2020-07-15T22:15:49.787Z"
name: "Article_2"
__v: 0
_id: "5f0f80157f7feb0a2512130a"
__proto__: Object
remember, passing javascript inside jsx requires {}
change :
return (
<Container>
<p>articleData<p>
</Container>
);
to
return (
<Container>
<p>{articleData}<p>
</Container>
);
there is a tiny mistake I think related to articles in the initial state of the article reducer the response is object but the initial state of articles is array here is what I mean:
const intialState = {
articles: [],
loading: false,
};
export default function (state = intialState, action) {
switch (action.type) {
case GET_ARTICLE:
return {
...state,
articles: {
[action.payload.name]: action.payload,
},
loading: false,
};
}
so instead of array change it to object like this:
const intialState = {
articles: {},
loading: false,
};
export default function (state = intialState, action) {
switch (action.type) {
case GET_ARTICLE:
return {
...state,
articles: {
[action.payload.name]: action.payload,
},
loading: false,
};
}
This is how I used to debug if something is not accessible from my store state
const mapStateToProps = (state) => {
console.log("My store state ===>", state); // log the `state` and see the exact path for articles
return ({
article: state.article.articles,
});
}
Edit
Default case is missing in reducer. Hope you have missed posting full code.
export default function (state = intialState, action) {
switch (action.type) {
case GET_ARTICLE:
return {
...state,
articles: {
[action.payload._id]: action.payload,
},
loading: false,
};
default: return state; // You should have default case
}
}

Update redux state object property

How do I update the property of an object in redux and preserve the rest of the object..
const appReducer = (state = initialState, action) => {
switch (action.type) {
case 'LOGIN_SUCCESS':
return Object.assign({}, state, {
user: { loggedIn: true, level: 'default' },
});
case 'UPDATE_PACKAGE': {
// add a new value for the user.level which would be in action.level
return { ...state, level: action.level };
}
default:
return state;
}
};
So I would expect the UPDATE_PACKAGE to change the contents of the redux store level property... but its unchanged...
So it seems like you're setting level on the root state instead of the user object.
This should fix it:
case "UPDATE_PACKAGE": {
return { ...state, user: { ...state.user, level: action.level } };
}

Categories

Resources