Im really struggling through this but I cannot get my component to rerender even though I can see the store is changing and yes Im not sure Im not mutating my original state.
Reducer:
const AssessmentReducer = (state = initialState, action) => {
switch (action.type) {
case GET_ASSESSMENT_INFO:
return { ...state, assessment: action.payload }
default:
return state
}
}
Action:
import { GET_ASSESSMENT_INFO } from '../reducers/AssessmentReducer'
import API from '../../api'
export function getAssessment(assessment) {
return {
type: GET_ASSESSMENT_INFO,
payload: assessment,
}
}
export function getAssesmentInfo(id) {
return function (dispatch) {
return API.get_all('assessments/' + id).then(
(response) => dispatch(getAssessment(response)),
(error) => console.log('An error occurred', error)
)
}
}
Component:
componentDidMount() {
const assessmentId = this.props.match.params.assessment_id
this.props.getAssesmentInfo(assessmentId)
}
/** A whole bunch of stuff in here ***/
render() {
console.log(this.props.assessment)
}
function mapStateToProps(state) {
return {
//screenQuestions: state.ScreenQuestionsReducer.screenQuestions,
assessment: state.AssessmentReducer.assessment,
}
}
export default connect(mapStateToProps, { getAssesmentInfo })(
withStyles(styles)(AssessmentTabs)
)
Im seeing my initial state being logged in the render, Can validate the action is called and dispatched to the reducer with the correct payload. But the console log in the render is never hit again. Using redux dev tools, the state is being updated correctly as well.
Any ideas?
EDIT:
as soon as a click a button in my component and update the state, it reads in the new props from redux no problem
Related
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);
}
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;
}
};
I am developing a Web application using React JS + Redux. I am new to React. What I am doing now is trying to set the state on one page and then retrieve the state in another page after redirection.
I have a Component called EventListComponent that displays the list of events. Inside that component, I change the state of a reducer calling an event.
This is the reducer function I call.
import * as EditEventActions from '../actions/edit.event.actions';
export default function (state = { }, action){
switch (action.type)
{
case EditEventActions.EVENT_SET_EDITING_EVENT:
return { ...state, event: action.payload }
default:
return state;
}
}
I fire the actions before redirecting to another page like this.
this.props.setEditingEvent(event);
this.props.history.push({
pathname : '/event/'+ event.id +'/edit'
});
In the new page, I render the component called, EditEventComponent.
This is the definition of the EditEventComponent
export class EditEventComponent extends React.Component{
constructor(props)
{
super(props);
alert(this.props.event.id)//cannot retrieve event here
}
render(){
return (
<h4>This is the Edit Event component</h4>
);
}
}
function mapStateToProps(state)
{
return {
event: state.editEvent.event
};
}
function matchDispatchToProps(dispatch)
{
return bindActionCreators({
}, dispatch);
}
const enhance = compose(withWidth(), withStyles(themeStyles, { withTheme: true }), connect(mapStateToProps, matchDispatchToProps))
export default enhance(EditEventComponent);
As you can see, inside the EditEventComponent I am trying to retrieve the event field of the state which is set in the previous page. But I cannot retrieve it.
My questions are
Is the state (of the redux store) reset after redirecting to the new page?
What is wrong with my code?
If what I am doing is not the right approach, what would be the best way to pass an object from one page to another in React Redux?
Here is my action
export const EVENT_SET_EDITING_EVENT = "(EVENT) SET EDITING EVENT";
export const setEditingEvent = (data) => ({
type: EVENT_SET_EDITING_EVENT,
payload: data
});
Here is the reducer
import * as EditEventActions from '../actions/edit.event.actions';
export default function (state = { }, action){
switch (action.type)
{
case EditEventActions.EVENT_SET_EDITING_EVENT:
return { ...state, event: action.payload }
default:
return state;
}
}
I expose the EventListComponent in this way as well.
const enhance = compose(withWidth(), withStyles(themeStyles, { withTheme: true }), connect(mapStateToProps, matchDispatchToProps))
export default enhance(EventListComponent);
You are probably not setting the type correctly in setEditingEvent action and the reducer returns the initial state since it doesn't hit EVENT_SET_EDITING_EVENT
I'm trying currently to pass the app.state contained to the Redux store in a React Component.
So far, this problem is still a deep mystery...
------> HERE THE GITHUB REPOSITORY OF MY CODE <------
Hope it will help to figure out what is wrong.
Abstract :
My problem is basically about mapStateToProps, is about link a Component to the state store, AFAIK the rest work very fine, but Something seems shortcut my this.props in React's Component, because either I use connect() or delete the mapStateToProps method, my Component stil display the initial state ..!
Redux resists me like an end-level's boss...
STATE OF PLAY
The provider with a store of react-redux: OK
Connect function pass to the props: OK
mapDispatchToProps works fine! So why the state fails to update the props since the connection seems well established?
I know my action is well mapped since when I delete the mapDispatch in the connect composition, the component then fails to trigger the corresponding action.
When console.log, the mapState receive effectively the store update but the Component stay blocked on initial state (tested with a "checkState" button on the component which returns the "store.getState().propertyTargeted"
HINTS :
when I delete the mapStateToProps in connect, my React.Component continue to receive the initialState,
so maybe there is an another source that overwrites my mapStateToProps, I seek for it currently
my this.props.state variable is called in the Component's constructor, maybe the constructor doesn't receive the store.updateState or something like that ? Another track to follow.
Here my combineReducer.js :
import { combineReducers } from "redux";
import {post} from "./status"
import {entry}from "./updateState";
// only one reducer active
const appReducer = combineReducers({
entry,
post
})
export default appReducer
Here my container.js :
const mapStateToProps = (state) => {
return { word: state.entry.word }
}
const mapDispatchToProps = {
postFile: postFileAction
}
const PostFileContainer = connect(mapStateToProps, mapDispatchToProps)(Component) ;
My postFile.js :
export const postFile = (word, base64Data) => dispatch => {
console.log("postFile httpRequest reached")
dispatch({
type: 'POST_WORD',
status: request
});
Axios.post("http://localhost:7500/api/files", {
"word": word,
"data": base64Data
}, {
"Content-Type": "multipart/form-data"
})
.then(res =>
dispatch({
type: 'POST_WORD',
status: success,
res
}))
.catch(err => {
dispatch({
type: 'POST_WORD',
status: error,
err
})
});
}
Here in my store.initialState :
initial state: {
"post": {},
"entry": {
"word": "initialWord"
}
}
the UPDATE_STATE_POSTWORD is provide by an other React component therefore dispatched to the store before that the bugging component trigger it own action with a updated word's entry.
Here my UPDATE_STATE_POSTWORD action snippet :
export const updateWord = word => {
return {
type: UPDATE_STATE_POSTWORD,
word
};
}
/// reducers.js part ///
postReducer.js :
export const post = (state ={}, action) => {
console.log("postStatus reached - reducer")
switch (action.status) {
case request:
console.log("Request start")
return state
case success:
switch (action.type) {
case POST_FILE:
console.log("request succeed: ", action.res)
var _id = action.res._id
// var word= action.res.word
return (Object.assign({}, state, {
_id
}))
case POST_WORD:
console.log("request succeed: ", action.res)
return (Object.assign({}, state, {
_id: ""
}))
default :
console.log(`default state on success case in
postStatusReducer`)
return state
}
case error:
console.log("request error: ", action.err)
return state
default:
return state
}
}
entryReducer.js :
const initialState = { word : "initialWord" }
export const updateStateReducer = (state= initialState, action) =>
{
switch (action.type) {
case UPDATE_STATE_POSTWORD:
var word = action.word
return (Object.assign({}, state, {
word
}))
default:
return state
}
}
Thanks
If you are using react-thunk, your action fn would receive dispatch and getState functions as arguments.
Running getState would give you actual state of the application. Recuired data would be passed to reducer and so on.
In your example RecordingAPI receives props that comes from redux only while initializing - in constructor.
You can fix your component by adding componentWillReceiveProps method
class RecordingAPI extends React.Component {
constructor(props) {
super(props);
...
this.state = {
word : this.props.word,
state: this.props
};
}
// new method that listens to props
componentWillReceiveProps (props) {
this.setState({
word: this.props.word,
state: this.props
});
}
checkState(e){
e.persist();
e.preventDefault();
e.stopPropagation();
console.dir(this.state.word)
console.dir(this.state.state)
}
render() {
...
return (
<div>
<button onClick={(e) => this.checkState(e)}> CheckState </button>
</div>
);
}
}
My current work-around is to import the store directly in my React Component then subscribe to the changes as it :
import {store} from "../App"
store.subscribe(() => {
// When state will be updated
// we will update local component state and force component to rerender
// with new data.
this.setState({
word: store.getState().entry.word // new entry.words at each update in the statge of the React.Component
});
});
ANSWER :
Assigning the store.state value to the Component's state constructor, the Component failed to update the state. So, referring to the store.state using this.props outside any assignment to the Component.state.property works like a charm*.
The trap is that storing a props in the props.constructor.state of the children works when you work only with React.js but this mechanism doesn't works for React-Redux then you have to stay the props outside any assignment in the props.constructor.state
I know it's me... Because I suck :)
But I believe I am doing everything correct but when I dispatch my action and the state changes my view does not re-render.
I believe this is the simple change that might be needed but the
render()
render(){
....
<div className={data.participants}>
+{store.getState().currentSex.participants}
</div>
....
}
Function that calls the action
onSetParticipants = () => {
console.info(store.getState()); //participants = 1
store.dispatch (currentSex.setParticipants(3));
console.info(store.getState()); //participants = 3
}
reducer currentSex.js
import { List, Map } from 'immutable';
const initialState = {
participants: 1
};
function currentSex (state = initialState, action) {
switch (action.type) {
case 'SET_PARTICIPANTS':
return {
...state,
participants:action.participants
}
}
return state
}
export default currentSex;
Actions
export const SET_PARTICIPANTS = 'SET_PARTICIPANTS';
export function setParticipants(participants) {
return {
type: SET_PARTICIPANTS,
participants: participants
}
}
How I have done my connect, as I believe this helps
function mapStateToProps(state, ownProps) {
return {
errorMessage: state.errorMessage,
inputValue: ownProps.location.pathname.substring(1)
}
}
export default connect(mapStateToProps, { })(App)
Please forgive me is this isn't enough or completely the wrong information.
But why does my page no re-render when i can see the state has changed?
edit
Its worth mentioning that my state has objects inside of it:
In your mapStateToProps you need to add the state that you want to render inside your component. In this case it looks like state.participants.
function mapStateToProps(state, ownProps) {
return {
errorMessage: state.errorMessage,
participants: state.participants,
inputValue: ownProps.location.pathname.substring(1)
}
}
And then use this.props.participants in your component.
import * as actions from '../actions';
/* ... */
render(){
....
<div className={data.participants}>
+{this.props.participants}
</div>
....
}
/* ... */
export default connect(mapStateToProps, actions)(App)
edit
And add the actions to your connect function, as well as importing them. Call your actions using this.props.currentSex(3) inside the function within your component that handles change events.