I am trying to get the state from redux store but whenever I access my redux action my component is loaded twice
By loading route manually first time it returns the two objects,one object of empty state and other object of updated state
However when I am switching between routes it returns the new state but twice each time or two objects of same state.
This causes undefined error on loading component specially when manually loading the route , when I am accessing any state property,
Redux action
export function getRelationshipStatus() {
let headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${localStorage.getItem('access_token')}`
}
return dispatch => {
axios.get('http://localhost/relation/api/get-relationship-status', { headers })
.then( response => dispatch({type:ActionTypes.GET_RELATIONSHIP_STATUS,payload:response.data}))
}
};
Reducer
import React from 'react'
import {GET_RELATIONSHIP_STATUS} from '../actions/action-types'
const initialState={
profile:{},
}
export default function (state=initialState,action) {
switch(action.type){
case GET_RELATIONSHIP_STATUS:
console.log(action.payload);
return {...state,profile:action.payload}
break;
default:
return state
}
}
Actual Component
import React, { Component } from 'react'
import {connect} from 'react-redux'
import {getRelationshipStatus} from '../../store/actions'
class People extends Component {
constructor(props){
super(props)
}
componentDidMount(){
this.props.getRelationshipStatus()
}
render() {
console.log(this.props.profile)
return (
<div>
</div>
)
}
}
function mapStateToProps(state) {
return {
profile: state.profile,
}
}
export default connect(
mapStateToProps,
{ getRelationshipStatus }
)(People);
Hey it's total natural behaviour of react-redux loading twice.
Even i can explain you but that's not question
I'm sure this behaviour is not problem
By the way what is error name?
Related
I'm writing a react-redux code I defined an action to called in the componant, it's called addCart.
import axios from "axios"
import {GET_PLATS} from "./actionType"
export const getplats = () => dispatch => {
// 2-1 axions get the same path of back in app.use
axios.get("/plat-list").then(res => {
dispatch({
//2-2 same name in action type (after this go to make reducers)
type:GET_PLATS,
payload:res.data
})
})
}
export const addCart =( ) =>{
return (dispatch) => {
console.log("added To cart");
dispatch({
type:GET_PLATS,
})
}
}
then I've wrote this reducer:
import { GET_PLATS } from "../action/actionType"
//first create first main state
const initialState={
plats:[],
cmdElements:[]
}
export default function(state=initialState,action){
switch(action.type){
case GET_PLATS:
return{
...state,
plats:action.payload,
cmdElements:state.cmdElements
}
default :
return state
}
}
Then I called this action in a component**
import React, { Component } from 'react'
import { connect } from 'react-redux'
import {getplats,addCart } from '../../action/action'
import PropTypes from 'prop-types'
const { Meta } = Card
class PlatListeU extends Component {
componentDidMount(){
this.props.getplats()
}
render() {
return (
<div>
<Button type="primary" onClick={ () =>{
this.props.platListe.addCart()
} } >addTocart</Button>
</div>
)}
PlatListeU.propTypes = {
addCart:PropTypes.func.isRequired,
PlatListe:PropTypes.object.isRequired
}
const mapStateToProps =(state) =>{
return{
platListe:state.plats ,
cmdElements:state.cmdElements
}
}
export default connect(mapStateToProps,{ getplats,addCart}) (PlatListeU)
But when I press on the button, I have this error message:
TypeError: this.props.platListe.addCart is not a function
Everything should be fine. I tried a lot of ways but the result is the same . Can anyone help me?
It's just this.props.addCart(). You import the methods in the component, not in platListe. Thus the error.
For the other error:
it looks like your reducers are mapped correctly. so state.moviesReducer is always defined.
if your initial list of items doesn't even load correctly, means your items object are causing the error.
if your initial list loads correctly, and the error occurs only after you dispatch the action, means your update() is mutating your state shape.
I don't know where you are getting this update function. but i am guessing you should just return{items:update(..)}
This is how I would go about debugging your code.
I think it is just this.props.addCart()
I believe you just want this.props.addCart(). The key platListe exists in your state object, it does not have any methods attached to it. You import the standalone methods at the top of your component.
How can I wait for react-redux to return my new connected component? Basically, I have an index screen where I make a query to a database to save the clients, the response of that api call is the argument with which I want to trigger my SAVE_CUSTOMERS action and then make a map in the view.
This error is because the object as such that I want to make the map does not yet exist, and this is why I forge a wait for that Hash and if it works.
I have several ways to force this to work, but I'm here for a fancy solution 😂
customers.js
import React from "react";
import bridge from "../../helpers/bridge/index";
import { save_customers } from "../../../actions/customers";
import CustomersUI from "../../components/Customers/CustomersUI";
import { connect } from "react-redux";
class CustomersScreen extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
bridge
.getCustomers(this.props.user.access_token)
.then((customers) => this.props.save_customers(customers))
.catch((error) => console.error(error));
}
render() {
return (
<CustomersUI
customers={this.props.customers}
/>
);
}
}
export default connect(
(state) => ({
user: state.user,
customers: state.customers,
}),
{
save_customers: save_customers,
}
)(CustomersScreen);
My reducer
export default (state = {}, action) => {
switch (action.type) {
case "SAVE_CUSTOMERS":
return action.customers;
default:
return state;
}
};
And... The action,
export function save_customers(customers) {
return {
type: "SAVE_CUSTOMERS",
customers,
};
}
Output
Obviously I have a combineReducers exporting everything.
Perhaps waiting for the component to be connected is not exactly the most fancy way to solve it, it is just the closest idea I have about it. Less than 1 week ago I am in React Native, never used Redux before. Thank you!
The customers array from your state might be undefined while it is waiting for the response from getCustomers. Therefore, on your render method, you should conditionally render the child CustomersUI only when customers is defined.
render() {
const { customers } = this.props;
return (
customers && (
<CustomersUI
customers={this.props.customers}
/>
)
);
}
Alternatively, the CustomersUI component should handle undefined values, such that it won't throw that error.
I have a Comment component that has a delete button. When the button is clicked, it called the action, makes the axios call, and when the call returns it dispatches the update to the reducer. The only problem is that it's not triggering the rerender of the parent component. The action, although it is updating the state, does not appear in the list of dispatched actions in the Redux DevTools. All other actions work and display in the DevTools, but for some reason this one doesn't.
My thought after reading the comment section below is that it's because I'm making a shallow copy of my object. Am I wrong to think that making a shallow copy, modifying a deeper object, and returning the shallow copy wouldn't trigger a rerender? Isn't the fact that the shallow object is a different reference enough to trigger it? I'm confident I'm doing this the same way in other places and I havenn't have a problem elsewhere. It
This is the action list in Redux DevTools after deleting the comment. I would expect that it would have "delete_comment" near the bottom somewhere, but it's not:
The data is passed from the parent components CommentList -> CommentThread -> Comment.
Is this truly dispatching?
This is a simplified component:
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {
deleteComment,
} from "../../actions/comment_actions";
class Comment extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
const {comment, data} = this.props;
if (!data) {
//console.log("mir_data doesnt exist");
return <div/>;
}
return (
<div key={"comment" + comment.id} id={"c" + comment.id}>
<button onClick={() => this.props.deleteComment(comment.id)}>Delete</button>
</div>
);
}
}
function mapStateToProps(state) {
return {
user: state.user
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
deleteComment,
}, dispatch)
}
export default connect(mapStateToProps, mapDispatchToProps)(Comment);
Here's a simplified action file:
export const DELETE_COMMENT = 'delete_comment';
export function deleteComment(id, callback = null) {
return (dispatch, getState) => {
axiosInstance.post('/delete-comment/', {comment_id: id}, getState().api.axios).then(
response => {
dispatch(dispatchDeleteComment(id));
//dispatch(dispatchViewUserInfo(response.data));
if (response.status === 200)
callback();
}
);
}
}
export function dispatchDeleteComment(id) {
return {
type: DELETE_COMMENT,
payload: id
};
}
Here's the simplified reducer:
import {DELETE_COMMENT} from "../actions/comment_actions";
export default function(state = {}, action){
let newState = {...state};
switch(action.type){
case DELETE_COMMENT:
//some logic
delete newState.comments[action.payload];
return newState;
default:
return state;
}
}
I don't know exactly how to approach this problem, and my research is turning up conflicting/confusing information. I'm using react, redux, saga, and react-router.
I have basically a master/detail scenario. I present the user with a list of stories and when they click on one, it loads a detail component with the details read from the state. However, I want users to be able to deep-link to the detail page if they know the detail ID. http://localhost:3000/story/1496620859347.
I am dispatching an action triggered in the component constructor, but the state that is mapped to the component props never changes. What am I doing wrong? (I've added some of the component code, but I'm not sure it is relevant.)
import React, { Component } from 'react';
import { connect } from 'react-redux';
import './FullStory.css';
import he from 'he';
import { downloadSelectedStoryByID } from '../store/actions/selected_story';
const mapStateToProps = (state) => {
return {
story: state.selected_story
}
}
const mapDispatchToProps = dispatch => {
return {
getStoryByID(id) {
dispatch(downloadSelectedStoryByID(id));
}
}
}
class FullStory extends Component {
constructor(props) {
super(props)
if (props.story.id == undefined) {
this.props.getStoryByID(props.match.params.id);
}
}
render() {
return (
)
Reducer
import c from '../../constants';
export const selected_story = (state={}, action) => {
switch(action.type) {
case c.DOWNLOAD_STORY_BY_ID_SUCCEEDED:
return action.payload;
case c.SET_SELECTED_STORY:
return action.payload;
default:
return state;
}
}
I put in the reducer.
EDIT: Ive changed my return to an object, yet still i'm getting empty props.
console.log of mapStateToProps(state) shows that temperature is empty. I am assuming I am getting back a non changed state, temperature from my axios call is not returned to my weatherPage.js.
my whole environment is working fine, im just trying to make an axios get request.
I'm having a bit of a difficulty passing my object through the Redux lifecycle, from the actions to the reducer while keeping the propTypes validation method and trying to use Object.assign() (which is truly the right way of mutating the state with a single deep copy as Dan Abramov noted.)
The error:
my props are empty. The axios call I've made in src/actions/weatherActions.js is not showing up as a prop.weatherDetails.temperature in src/components/weatherPage.js
, it returns my default state.
I'm new to ES6 and Redux, I've included propTypes into my page and I'm having bit of an issue with this, I think the issue comes from supplying the right state that comes from the action.
When the choose button is pressed i'm supposed to receive the temp_c (axios calls this json)
src/components/weatherPage.js
import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {withRouter} from 'react-router';
import * as WeatherActions from '../../actions/weatherActions';
class WeatherPage extends React.Component {
render() {
return (
<div>
<h2>temps: {this.props.weatherDetails.temperature}</h2>
<input
type="submit"
onClick={this.onClickSave.bind(this)}
value="CHOOSE"/>
</div>
);
}
onClickSave() {
WeatherActions.getWeather(this.props.dispatch);
}
WeatherPage.propTypes = {
weatherDetails: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
};
function mapStateToProps(state) {
return {
weatherDetails: state.weathers.weatherDetails
};
}
export default connect(mapStateToProps)(withRouter(WeatherPage));
Since this.props.weatherDetails.temperature shows my current state, I know that problem lies between the action and the reducer.
src/actions/weatherActions.js
import axios from 'axios';
export const ActionTypes = {
WEATHER: { LOAD_WEATHER: 'WEATHER.LOAD_WEATHER' } };
export function getWeather(dispatch) {
console.log('in getWeather method');
console.log('this is getWeather dispatch: ', dispatch);
axios({
url: 'http://api.weatherunlocked.com/api/trigger/32.08,34.78/current%20temperature%20gt%2016%20includecurrent?app_id=ba2f68f0&app_key=0356747cc4d1d4ba0dd5cc25a0c86743',
method: 'get'
}).then(function (response) {
//console.log('in the then func with this res: ', JSON.stringify(response));
dispatch({
type: ActionTypes.WEATHER.LOAD_WEATHER,
temperature: response.CurrentWeather.temp_c
},
function () {
console.log('dispatch completed');
});
});
console.log('end of class getWeather');
I'm performing a simple axios call, yet i'm not sure if i'm dispatching the 'payload' (temperature: response.CurrentWeather.temp_c) correctly to appear through the reducer and back into view.
Here is my reducer:
src/reducers/weatherReducer.js
import * as WeatherActions from '../actions/weatherActions';
const initialState = {
weatherDetails: {
area: '',
temperature: 'sdf'
}
};
function WeatherReducer(state = initialState, action) {
console.log('in WeatherReducer, this is action: ' + JSON.stringify(action));
switch (action.type) {
case WeatherActions.ActionTypes.WEATHER.LOAD_WEATHER:
return [...state, Object.assign({}, action.temperature.data)];
default:
return state;
}
}
export default WeatherReducer;
What am I missing here on this build?
You state object must be returned as an object rather than an array from the reducer like
switch (action.type) {
case WeatherActions.ActionTypes.WEATHER.LOAD_WEATHER:
return Object.assign({}, state, action.temperature.data);
default:
return state;
}