how to get data from redux in componentDIdMount? - reactjs

In console nothing, where can be a mistake ?
Need to get this.props.about and check empty or not.
reducer.js
export default function details(state = initialState, action) {
switch(action.type) {
case DETAILS_SUCCESS:
return { ...state, details: action.payload, error: '' };...
Container.js
class HeaderContainer extends Component {
render() {
const { details } = this.props, { deTails } = this.props.HeaderAction;
return <div><Header deTails={deTails} about={details.details} error={details.error} /></div>
}
}
function mapStateToProps(state) {
return {
details: state.details,
}
}
function mapDispatchToProps(dispatch) {
return {
HeaderAction: bindActionCreators(HeaderAction, dispatch),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(HeaderContainer);
Component.js
componentDidMount() {
console.log(this.props.about);
}

You won't receive updated state as in props in componentDidMount rather you can use:
componentWillReceiveProps(nextProps){ // this is UN_SAFE
}
or
static getDerivedStateFromProps(nextProps, prevState) { // this is recommended
}

Related

mapStateToProps() in Connect() must return a plain object. Instead received undefined

I have a problem with displaying data.
In my application I use react and redux.
In the console I will get an error mapStateToProps() in Connect(ListPets) must return a plain object. Instead received undefined.
This is my main component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import loadData from '../actions/actions';
class ListPets extends Component {
componentDidMount() {
const { loadData } = this.props;
loadData();
console.log(loadData );
}
render() {
const { dataPet } = this.props;
return (
<div>
</div>
);
}
}
const mapStateToProps = (state) => {
return state;
};
const mapDispatchToProps = (dispatch) => {
return {
loadData: () => dispatch(loadData())
}
};
This fragment console.log(loadData ); display
ƒ loadData() {
return dispatch(Object(_actions_actions__WEBPACK_IMPORTED_MODULE_7__["default"])());
}
When I add the code {dataPet.data} in div. I get an error]. As if this data was not in the store, I do not know...
this my reducer function
const initialState = {
isFetching: false,
dataPet: [],
};
const fetchDataReducer = (state=initialState, action) => {
switch(action.types) {
case actionTypes.FETCH_DATA_START:
return {
...state,
isFetching: true,
}
case actionTypes.FETCH_DATA_SUCCESS:
return {
...state,
isFetching: false,
dataPet: action.dataPet,
}
case actionTypes.FETCH_DATA_FAIL:
return {
...state,
isFetching: false,
}
};
}
Data is well downloaded, because the console receives the FETCH_DATA_SUCCESS action.
I have no idea how to solve this problem
I made some changes on your code, try this now...should work
https://codesandbox.io/s/z2volo1n6m
In your reducer you have a typo:
const fetchDataReducer = (state=initialState, action) => {
switch(action.types) { // here
It should be action.type not action.types.
If thing is an object in state:
const mapStateToProps = state => ({
thing: state.thing,
});
Then use like:
this.props.thing in your component

React Redux state change

this.props.authState stays the same although I'm dispatching an action in my componentDidMount function:
componentDidMount() {
if (localStorage.getItem('token')) {
dispatch(updateAuthState('AUTHENTICATED'));
}
}
render() {
<div>{this.props.authState}</div>
}
Home.propTypes = {
authState: PropTypes.string
};
const mapStateToProps = (state) => {
return {
authState: state.authState
}
};
const mapDispatchToProps = (dispatch) => {
return {
}
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
the output is NO_AUTH (the initial value of authState)
Reducer:
export function authState(state = "NO_AUTH", action) {
switch (action.type) {
case 'AUTH_STATE':
return action.authState;
default:
return state;
}
}
any idea why?
You're currently dispatching directly inside the componentDidMount which isn't mapped into:
connect(mapStateToProps, mapDispatchToProps)(Home);
This should do the job:
componentDidMount() {
if (localStorage.getItem('token')) {
this.props.onUpdateAuthState('AUTHENTICATED');
}
}
const mapDispatchToProps = (dispatch) => {
return {
onUpdateAuthState: function(authState) {
dispatch(updateAuthState(authState));
}
}
};
Now, this will get the authState:
const mapStateToProps = (state) => {
return {
authState: state.authState
}
};
If you’re mutating the state then component will not be re rendered. You need to return {...state, authState} from your reducer.
And you verify your updated state in
componentWillReceiveProps(nextProps)
{
}
I hope this would solve the issue.

How to pass internal state to global state using Redux

I'm using Redux in an application for the first time and having trouble understanding how to pass a component's internal state to the global state object.
export default class ComponentOne extends Component {
constructor() {
this.state = {
number: 0
}
handleNumber = (e) => {
this.setState({
number: e.target.value
})
}
render() {
console.log(this.state.number)
return (
<div>
<input onChange={this.handleNumber} type="number">
</div>
)
}
}
}
function mapStateToProps(state) {
return {
number: state
}
}
export default connect(mapStateToProps, { HANDLE_NUMBER_CHANGE })(ComponentOne);
My Actions & Reducers:
const HANDLE_NUMBER_CHANGE = state => {
return {
type: 'HANDLE_NUMBER_CHANGE'
}
}
export default (state = 0, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
//Im lost here - trying to save internal state
default:
return state;
}
}
My store is set up properly, using redux-thunk for middleware.
When I log store.getState() - it is logging 0 regardless of my components internal state.
Can anybody explain how this works?
When you have global state you dont need to save it to the local state. It is accessible to the component as this.props.value.
The way to set global state is by passing the value to the action creator, which returns it in the action. The reducer gets it in the action object and saves it.
There are many simple examples available. Here is one.
Here is your code after changes:
(I didn't run it - there might be errors, but I believe that you will be able to fix them by yourself; I have divided the code between several files - this is how usually how this is done. Look in the example in the above link if you have problems)
// file: src/components/ComponentOne.js
import React from 'react';
import { connect } from 'react-redux';
import { handleNumber } from '../actions';
class ComponentOne extends Component {
constructor(props) {
super(props);
this.handleNumber = this.handleNumber.bind(this);
}
render() {
console.log(this.state.number)
return (
<div>
<input onChange={(e) => this.props.handleNumber(e.target.value)} type="number" />
</div>
);
}
}
function mapStateToProps(state) {
return {
number: state
}
}
export default connect(mapStateToProps, { handleNumber })(ComponentOne);
// end of file
/// separate file: src/reducers/index.js ////
import { combineReducers } from 'redux';
import dataReducer from './dataReducer';
export default combineReducers({
number: dataReducer
});
// end of file
// separate file: src/reducers/dataReducer.js
const DataReducer = (state = 0, action) => {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return action.payload;
default:
return state;
}
};
export default DataReducer;
// end of file
// separate file: src/actions/index.js
export function handleNumber(value) {
return ({
type: 'HANDLE_NUMBER_CHANGE',
payload: value
});
}
I don't see the logic in making your internal state equal your store. I'm not saying you're wrong, but it doesn't seem to fit within the redux paradigm. However...
Action should be...
export function HANDLE_NUMBER_CHANGE = number => {
return {
type: 'HANDLE_NUMBER_CHANGE'
payload: number
}
}
Reducer should look like...
export default (state = {number: 0}, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return (state = {
...state,
number: action.payload,
});
Lastly, you'll need to call a dispatch from your onChange function.
dispatch(HANDLE_NUMBER_CHANGE(e.target.value).
If you do not pass the value to the action, there is no way for the reducer to add it to the store.
If you are managing your ComponentOne state using redux then you dont need
react state.
ComponentOne
export default class ComponentOne extends Component {
constructor() {
handleNumber = (e) => {
this.props.updateNumber(e.target.value);//call dispatch method
}
render() {
return (
<div>
<input onChange={this.handleNumber} type="number">
</div>
)
}
}
}
function mapStateToProps(state) {
return {
number: state.number //map updated number here
}
}
function mapDispatchToProps(state) {
return {
updateNumber(number){
dispatch({type: 'HANDLE_NUMBER_CHANGE',number});//dispatch action
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ComponentOne);
reducers:
export default (state = 0, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return {
...state,number : actio.number//update number here
}
default:
return state;
}
}

React Native: componentWillUpdate not called

I'm creating a React Native app using React Navigation and Redux.
class LoginScreen extends Component {
state = {
email: '',
password: '',
errors: {
email: '',
password: ''
}
}
onPressLogin() {
this.props.signIn(this.state.email, this.state.password);
}
componentWillUpdate(nextProps, nextState) {
console.log("component will update");
if (nextProps.signedIn) {
this.props.navigation.navigate('LoggedIn');
}
}
render() {
if (this.props.signedIn) {
this.props.navigation.navigate('LoggedIn');
}
return(<View>...</View);
this.props.signIn() is a Redux action, which for now just updates the state as such: { signedIn: true }. The following code is where I pass the Redux actions and state as props.
function mapStateToProps(state, props) {
return {
signedIn: state.authReducer.signedIn,
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(Actions, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
When the action is fired, the state updates as I would expect and render() is called. If I put the navigation code in the render() function everything works fine. To make the code cleaner, I want to move it into componentWillUpdate() but this function is not firing. The console log never gets printed to the console.
Here is my action and my reducer.
Action:
export const SIGN_IN_SUCCESS = 'SIGN_IN_SUCCESS';
export const SIGN_IN_FAIL = 'SIGN_IN_FAIL';
export function signIn(email, password) {
return (dispatch) => {
dispatch({ type: SIGN_IN_SUCCESS });
}
}
Reducer:
import { combineReducers } from 'redux';
import {
SIGN_IN_FAIL,
SIGN_IN_SUCCESS
} from '../actions/';
let authState = { signedIn: false, error: '' }
const authReducer = (state = authState, action) => {
switch(action.type) {
case SIGN_IN_SUCCESS:
return {...state, signedIn: true }
case SIGN_IN_FAIL:
return {...state, signedIn: false, error: action.error }
default:
return state;
}
}
const rootReducer = combineReducers({
authReducer
});
export default rootReducer;
Because you executed navigation right inside render() function:
render() {
if (this.props.signedIn) {
this.props.navigation.navigate('LoggedIn');
}
return(<View>...</View);
}
It must be:
render() {
return !this.props.signedIn && (<View>...</View);
}

Redux: Updating the store with simultaneous dispatch

I am trying a simple example of rendering 2 components via dispatching an action on componentWillMount() which updates the store.
Initial State:
export default {
dashboards: [],
dashboardContent: []
};
2 Reducers:
export default function dashboardContentReducer(state = initialState.dashboardContent, action) {
switch(action.type) {
case types.LOAD_DASHBOARD_CONTENT_SUCCESS:
return action.dashboardContent;
default:
return state;
}
}
and
export default function dashboardReducer(state = initialState.dashboards, action) {
switch(action.type) {
case types.LOAD_DASHBOARDS_SUCCESS:
return action.dashboards;
default:
return state;
}
}
Here's where things get a little weird.
I am able to dispatch the action to call these reducers, but only 1 of them will function to update the redux store. I do so as follows:
class NavigationBar extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.dispatch(dashboardActions.loadDashboards());
}
render() {
return (
<div className="rc-navigationBar">
<h1>Navigation!</h1>
{this.props.dashboards.map((dashboard, index) => {
return <h1 key={index}>{dashboard.title}</h1>
})}
</div>
);
}
}
and for the other:
class ContentPage extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.dispatch(dashboardContentActions.loadDashboardContent(extractIdFromRoute()));
}
render() {
return (
<div>
<h1>Content!</h1>
{this.props.dashboardContent.map((content, index) => {
return <h1 key={index}>{content.application}</h1>;
})}
</div>
);
}
}
When I simultaneously try to modify the store, I get this error:
Uncaught (in promise) Error: A state mutation was detected between dispatches, in the path 'dashboards.1.filter.Pivot.ancestorOrigins'. This may cause incorrect behavior.
What am I doing wrong here?
You are returning it in a wrong way. It should be like this -
export default function dashboardContentReducer(state = default, action) {
switch(action.type) {
case types.LOAD_DASHBOARD_CONTENT_SUCCESS:
return Object.assign({}, state, { dashboardContent:action.dashboardContent });
default:
return state;
}
}

Resources