React Native - Redux ~ Props updating when not getting called - javascript

I am experiencing an issue with React Native whilst using Redux.
I am using a Redux state to show/hide a modal from one component to the other. As this seems to be the best solution considering that it is cross component.
I have the modal opening and closing perfectly fine, and that works exactly how it show. However, when I click on this, it seems as though the props for the parent component are getting updated to the initial state again and I'm unsure as to why.
Parent Component:
const mapStateToProps = state => {
return {
modalVisible: state.modals.addRoomModalVisible
}
};
const mapDispatchToProps = dispatch => {
return {
onMakeAddRoomModalActive: () => dispatch(makeAddRoomModalVisible())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(RoomsScreen);
Child Component
const mapStateToProps = state => {
return {
rooms: state.rooms.rooms
}
};
const mapDispatchToProps = dispatch => {
return {
onGetRooms: () => dispatch(getRooms())
}
};
export default connect(mapStateToProps, mapDispatchToProps)(RoomList);
Modals Reducer
import { HIDE_ADD_ROOM_MODAL, SHOW_ADD_ROOM_MODAL } from "../actions/actionTypes";
const initialState = {
addRoomModalVisible: false
};
const modalsReducer = (state = initialState, action) => {
switch (action.type) {
case SHOW_ADD_ROOM_MODAL:
return {
...state,
addRoomModalVisible: true
};
case HIDE_ADD_ROOM_MODAL:
return {
...state,
addRoomModalVisible: false
};
default:
return initialState;
}
};
export default modalsReducer;
It seems the issue lies when I call the onMakeAddRoomModalActive prop. I have console logged out and the state is getting reset and the this.props.rooms is getting set to and empty array which is the initialState object which I have defined.

The issue lay within all of my reducers.
At the end of each reducer case statement I did a default which set the state to be the initialState which was defined at the top of the reducer.
I needed to change this to return state instead.
const modalsReducer = (state = initialState, action) => {
switch (action.type) {
case SHOW_ADD_ROOM_MODAL:
return {
...state,
addRoomModalVisible: true
};
case HIDE_ADD_ROOM_MODAL:
return {
...state,
addRoomModalVisible: false
};
default:
return state;
}
};

Related

React UI doesn't update on redux store change

I have a redux State HOC to manage the connection
I Have a problem when I add a new post to the store
import React, { useEffect } from "react";
import { connect } from "react-redux";
export default function withState(WrappedComponent) {
function mapStateToProps(reduxState) {
let state = {};
for(let t of Object.entries(reduxState)) {
state = {...state, ...t[1]}
}
return {
...state,
};
}
return connect(
mapStateToProps,
null
)(function (props) {
useEffect(() => {}, [props.posts, props.comments]) /*tried this but didn't work*/
return (
<React.Fragment>
<WrappedComponent {...props} />
</React.Fragment>
);
});
}
I am trying to make the program render the response from my back-end without me reloading the page manually
I tried using the useEffect
and I saw through the dev tools that the state change correctly
my reducer
import { GET_ALL_POSTS, CREATE_NEW_POST } from "../actions"
const initialState = {
posts: []
}
export default function postReducer(state = initialState, action) {
let newState = {...state}
switch(action.type){
case GET_ALL_POSTS:
return {
...newState,
posts: [...action.posts],
}
case CREATE_NEW_POST:
const posts = [...newState.posts, action.post]
return {
...newState,
posts
}
default:
return {
...newState,
}
}
}
I also read that react changes doesn't respond to shallow copies so I changed the whole array in the post reduces when I add a new post
Your withState HOC is very strange. I'm not sure why you don't just use connect directly (or use hooks). But try this:
export function withState(WrappedComponent) {
return connect(
(state) => ({
posts: state.postsReducer.posts,
comments: state.commentsReducer.comments
}),
null
)(WrappedComponent);
}

React Redux - boolean value is undefined

I want process a plain boolean value with my Redux store. But this value results into undefined on every dispatch event. Does any of you see why?
I have the following setup:
reducer.js
const initialState = {
canSwipe: true
};
export default function rootReducer(state = initialState, action) {
switch (action.type) {
case CAN_SWIPE: {
console.log(action.payload.canSwipe) // This logs true or false - works!
return action.payload.canSwipe
}
default:
return state;
}
}
actions.js
export const setSwipeState = canSwipe => ({ type: CAN_SWIPE, payload: { canSwipe } });
component for dispatching
function MapOverlay({setSwipeState}) {
const zoom = 5;
return (
<Map
onMovestart={() => setSwipeState(false)}
onMoveend={() => setSwipeState(true)}
>
{...}
</Map>
)
}
export default connect(null, {setSwipeState})(MapOverlay);
The reducer should return data which must be compliant with your initial state:
const initialState = {
canSwipe: true
};
So you need to change your reducer to respect this structure:
switch (action.type) {
case CAN_SWIPE: {
console.log(action.payload.canSwipe) // This logs true or false - works!
return {canSwipe: action.payload.canSwipe}
}

How to reset a reducer which uses the same key but a different action?

So this is my current reducer:
import { Reducer } from 'redux';
import {
EventState,
LOAD_EVENTS,
LOAD_EVENT_BY_ID,
FETCH_MORE_EVENTS
} from '../types/eventTypes';
export const initialState = {
eventsList: [],
event: undefined,
isLastPage: false
};
const eventReducers: Reducer<EventState, any> = (
state = initialState,
action
) => {
switch (action.type) {
case LOAD_EVENTS:
return {
...state,
eventsList: action.eventsList
};
case FETCH_MORE_EVENTS:
return {
state,
eventsList: state.eventsList.concat(action.eventsList),
isLastPage: action.eventsList.length === 0
};
default:
return state;
}
};
export default eventReducers;
As you see both cases LOAD_EVENTS and FETCH_MORE_EVENTS share the key eventsList, on fetch more events I am calling state like this state instead of ...state because it seems to re init the state of the whole reducer. But, is that the proper way? I think that if this reducer grows up, that will be a bug.
So what can I do to clean that reducer properly to make? Like all I need is that LOAD_EVENTS fires then eventsList should get clear and fill out again by what LOAD_EVENTS brings. And basically I only need to reset the state of eventsList but rest should remain the same.
when you calling state like state instead of ...state, you aren't re-init the state, but storing the previous state inside the new state, like this example below:
state = {
eventsList: [...someEvents],
event: undefined,
isLastPage: false,
state: {
eventsList: [...someEvents],
event: undefined,
isLastPage: false,
state: {
eventsList: [...someEvents],
event: undefined,
isLastPage: false
}
}
};
This is not a good pattern/practice, only if is super necessary.
So the correct, it's reset the previous state with initialState when fetch more events.
export const initialState = {
eventsList: [],
event: undefined,
isLastPage: false
};
const eventReducers: Reducer<EventState, any> = (
state = initialState,
action
) => {
switch (action.type) {
case LOAD_EVENTS:
return {
...state,
eventsList: action.eventsList
};
case FETCH_MORE_EVENTS:
return {
...initialState,
eventsList: state.eventsList.concat(action.eventsList),
isLastPage: action.eventsList.length === 0
};
default:
return state;
}
};
But how you say, it's only need to reset the state of eventsList but rest should remain the same, you can keep the same to this reducer:
case LOAD_EVENTS:
return {
...state,
eventsList: action.eventsList
};
Because when you set eventsList like the example above, you are reset the eventsList and fill out again with new data. But don't forget the problem about the first example that I say.

Implementing Redux in React using the create-react-app -Simple question

Is is correct to pass a reducer as props when i'm using a rootreducer ?
This is my rootReducer.js :
import { combineReducers } from 'redux';
import simpleReducer from './simpleReducer';
import messageReducer from './messageReducer';
import NewReducer from './NewReducer';
export default combineReducers({
simpleReducer,messageReducer,NewReducer
});
And this is one of my action creators addMessage.js
export const addMessage = (message) => dispatch => {
dispatch({
type: 'ADD',
message: message
})
}
Here is the first reducer messageReducer.js
export default (state = [], action) => {
switch (action.type) {
case 'ADD':
return [
...state,
action.message
];
default:
return state;
}
};
And here is another one simpleReducer.js
export default (state = {}, action) => {
switch (action.type) {
case 'SIMPLE_ACTION':
return {
result: action.payload
}
default:
return state
}
}
And finally here is my last reducer NewReducer.js
export default (state = '', action) => {
switch (action.type) {
case 'AnyThing':
return action.WhatToDisplay;
default:
return state;
}
};
Here is my mapping in the App.js
const mapStateToProps = state => ({
...state
})
const mapDispatchToProps = dispatch => ({
simpleAction: () => dispatch(simpleAction()),
submitNewMessage: (message) => {
dispatch(addMessage(message))
},
NewAction: () => dispatch(NewAction())
})
And here is my ِApp Component.Notice my last 2 h2 tags as well as my ul tag .Without me adding the reducer at the end of the prop , it doesn't work.So
is what i'm doing right ? or is there another way to show the redux state in
my react ?.Note that i currently have no errors and the code functions well.I
just wana know if what i am doing is right or wrong and if there is a better
syntax to show the redux state in my create react app.
class App extends Component {
constructor(props) {
super(props);
this.state = {
input: ''
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.props.submitNewMessage(this.state.input);
this.setState({
input: ''
});
}
simpleAction = (event) => {
this.props.simpleAction();
}
localNormalFunction=(event)=>{
this.props.NewAction()
}
render() {
return (
<div >
<h1>fjasgdasdsg</h1>
<button onClick={this.simpleAction}>Test redux action</button>
<pre>
{
JSON.stringify(this.props)
}
</pre>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.props.messageReducer.map( (message,idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul><br/><br/>
<button onClick={this.localNormalFunction}>dsadsdsa</button>
<h2>{this.props.NewReducer}</h2>
<h2>{this.props.simpleReducer.result}</h2>
</div>
);
}
}
It is better practice to get only the props you need from redux in each component. If you pass the whole redux state in mapStateToProps then whenever anything in redux changes you will have everything rerendering even if nothing you use changed.
One common reason you might be getting errors is that you are trying to use the props in render and they get instantiated afterwards.
Try this give default values to the props if you can't get them from redux:
App.defaultProps = {
result: '',
NewReducer: '',
messageReducer: []
}
const mapStateToProps = state => ({
result: state.simpleReducer.result,
NewReducer: state.NewReducer,
messageReducer: state.messageReducer
})
and then change this.props.simpleReducer.result to this.props.result

React Redux mapStateToProps loads data in the second call

mapStatToProps is callings it's self twice and loads data on the second call but then doesn't assign it to components as a prop and returns an empty array.
The Reducer:
export default function postsReducer(state = initialState.posts, action) {
switch (action.type) {
case types.LOAD_POSTS_SUCCESS:
return action.posts;
default:
return state;
}
}
Here is my mpStateToProps func:
function mapStateToProps(state, ownProps) {
const singlePost = state.posts.filter(post => post.code == ownProps.params.id);
return {
post: singlePost
};
}
Here is my Component's state:
this.state = {
post: [...props.post]
};
Your code is probably right, but it seems like you forgot to update your state.post value when your component receives new props.
componentWillReceiveProps(nextProps) {
this.setState({
post: nextProps.post
});
}

Categories