mapStateToProps method is not invoked - reactjs

For some reason my "secondComponent" isn't actually having mapStateToProps invoked at all, even with a console.log() in it and I am actually quite confused as to why this might be. Redux is working perfectly with my "App" component, but without mapStateToProps being called in the child component it's left in the dark.
Hoping someone could help me here!
1: Index.tsx, where I do make sure to have a Provider for the store.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux';
import configureStore from './store';
const store = configureStore;
ReactDOM.render(
<Provider store={store()}>
<App />
</Provider>,
document.getElementById('root')
);
2: My "App" component that works with the redux store without issue.
import * as React from 'react';
import { connect } from 'react-redux';
import { addItemToCart, removeItemFromCart } from './store/cart/actions';
import { Button, Grid } from 'semantic-ui-react';
import { RootState } from './store';
import { SecondComponent } from './components/SecondComponent';
export interface IAppProps {
addItemToCart: typeof addItemToCart,
removeItemFromCart: typeof removeItemFromCart,
userId: number,
selectedItems: number[]
}
export class App extends React.Component<IAppProps> {
onClickAdd() {
this.props.addItemToCart(5);
}
public render() {
return (
<Grid centered>
<SecondComponent/>
</Grid>
);
}
}
const mapStateToProps = (state: RootState) => {
return {
userId: state.cart.userId,
selectedItems: state.cart.selectedItems
};
}
export default connect(
mapStateToProps,
{ addItemToCart, removeItemFromCart }
)(App);
3: The second component that doesn't have "mapStateToProps" invoked at all. :(
import * as React from 'react';
import { RootState } from '../store';
import { connect } from 'react-redux';
import { addItemToInventory, removeItemFromInventory } from '../store/inventory/actions';
import { Item, ItemTypesAvaliable } from '../store/inventory/types';
import { Fragment } from 'react';
import ItemTypeSection from './ItemTypeSection';
import { Grid } from 'semantic-ui-react';
export interface ISecondComponentProps{
removeItemFromInventory?: typeof removeItemFromInventory,
addItemToInventory?: typeof addItemToInventory,
items?: Item[],
itemTypesAvaliable?: ItemTypesAvaliable[]
}
export class SecondComponentextends React.Component<ISecondComponentProps> {
public render() {
let { itemTypesAvaliable } = this.props;
console.log(this.props);
return (
<Grid>
ok?
{itemTypesAvaliable != null ? itemTypesAvaliable.map(individualItemType => {
return <ItemTypeSection itemType={individualItemType} />
}) : <h1>doesn't work</h1>}
</Grid>
);
}
}
const mapStateToProps = (state: RootState) => {
console.log(state);
console.log("no???")
return {
// items: state.inventory.items,
// itemTypesAvaliable: state.inventory.itemTypesAvaliable
};
}
export default connect(
mapStateToProps,
{ addItemToInventory, removeItemFromInventory }
)(SecondComponent);```

Please make sure that you are importing the required instance. In your case, you need the redux connected instance of SecondComponent with the code
Right:
import SecondComponent from <pathToSecondComponentFile>
which is generating through
export default connect(
mapStateToProps,
{ addItemToInventory, removeItemFromInventory }
)(SecondComponent);
if you are importing the component like this
Wrong:
import {SecondComponent} from "<pathToSecondComponentFile>"
then please remove the braces of SecondComponent to get the default instance of export from file.

Related

Need help! React Component Export not working >_<

Im having this issue where even though I'm exporting both components
SearchBar & MainCard I keep getting this error message in my
App.js file. Any feedback is appreciated!
Error:
./src/App.js - Attempted import error: 'MainCard' is not exported from './components/ui-componets/SearchBar'.
App.js
import React, { Component } from 'react';
import { Container, Theme } from '#customLibrary/core'
import { connect } from 'react-redux';
import { fetchComponent } from './actions';
import TopMenu from './components/ui-componets/TopMenu';
import {SearchBar,MainCard} from './components/ui-componets/SearchBar';
class App extends Component {
state = {
visible: true,
width: 13,
}
handleClick = () => {
this.setState({ visible: !this.state.visible, width: 16 })
}
render() {
const { userData } = this.props;
const { visible } = this.state;
return <Theme>
<Container width='3379px'>
</Container>
<Container width='3379px'>
<TopMenu onClick={this.handleClick} userData={userData} />
</Container>
<Container width='3379px'>
<SearchBar />
</Container>
<Container width='3379px'>
<MainCard/>
</Container>
</Theme>
}
}
const mapStateToProps = (state) => {
return {
userData: state.user
}
}
export default connect(mapStateToProps, { fetchComponent })(App);
SearchBar.js
import React, { Component } from 'react';
import { IS_FETCHING_DBUSERS, FETCH_DBUSERS_SUCCESS, IS_FETCHING_ROLES, FETCH_ROLES_SUCCESS, IS_FETCHING_RESOURCES, FETCH_RESOURCES_SUCCESS } from '../../actions/keys';
import { users, Roles, Resources } from '../../actions/URI';
import { fetchComponent } from '../../actions/index';
import { connect } from 'react-redux';
import _ from 'lodash';
import {
Theme,
Grid, Form, Icon, Container, Loader,
Card, Typography, Tabs
} from '#customLibrary/core';
class SearchBar extends Component {
...
}
class MainCard extends Component {
...
}
const mapStateToProps = state => {
return {
Users: state.users,
roles: state.roles,
resources: state.resources,
}
}
export default connect(mapStateToProps, { fetchComponent })(SearchBar,MainCard);
import {SearchBar,MainCard} from './components/ui-componets/SearchBar';
You have used default export while exporting, but using the syntax for named imports while importing.
import CustomName from './components/ui-componets/SearchBar';
should work
Issue: You've not correctly exported MainCard, and you export them as a default export (i.e. only one component is exported), but you import them as named exports.
export default connect(mapStateToProps, { fetchComponent })(SearchBar,MainCard);
Solution: From what I know, the connect HOC can only decorate a single component at a time. If you want to export both then you'll need to connect both individually as named exports (i.e. remove the default keyword.
export const ConnectedSearchBar = connect(mapStateToProps, { fetchComponent })(SearchBar);
export const ConnectedMainCard = connect(mapStateToProps, { fetchComponent })(MainCard);
Now the import in App will work
import { SearchBar, MainCard } from './components/ui-componets/SearchBar';

How to fix Uncaught TypeError: Cannot read property 'getState' of undefined?

I am trying to use React with Redux for the frontend part with django rest framework in the backend. Got the issue getState in Provider tag in App component because of issue in store. And when i try to use the map function in the Words.js, I get error of undefined use of map. And I believe this is because of value of the array is null. Hence to fixed this error of getState.
Got this error even on including the store in Provider of App component when a reducers was not defined.
When I load a static array it does get rendered properly in the specific component.
This is Redux Store in the filename:store.js
import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';
import rootReducer from './reducers'
const initialState = {};
const middleware = [thunk];
const enhancer = composeWithDevTools(applyMiddleware(...middleware));
const store = createStore(
rootReducer,
initialState,
enhancer
);
export default store;
The index.js file is below
import App from './components/App'
import ReactDOM from 'react-dom';
import React from 'react';
ReactDOM.render(<App />, document.getElementById("app"));
They action types file types.js using django rest_framework to create the data.
export const GET_WORDS = "GET_WORDS";
The action file words.js
import { GET_WORDS } from "./types";
import axios from 'axios';
export const getWords = () => dispatch => {
axios.get('/api/words/')
.then(res => {
dispatch({
type: GET_WORDS,
payload: res.data
});
}).catch(err => console.log(err));
}
combined reducer file
import { combineReducers } from "redux";
import words from './words';
export default combineReducers({
words
});
The reducer file word.js
import { GET_WORDS } from '../actions/types';[enter image description here][1]
const initialState = {
words: []
}
export default function (state = initialState, action) {
switch (action.type) {
case GET_WORDS:
return {
...state,
words: action.payload
}
default:
return state;
}
}
The Component in which the words list will be called: Words.js
import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { getWords } from "../../../actions/words";
export class Words extends Component {
static propTypes = {
words: PropTypes.array.isRequired,
getWords: PropTypes.func.isRequired
};
componentDidMount() {
this.props.getWords();
}
render() {
return (
<Fragment>
Hi
</Fragment>
)
}
}
const mapStateToProps = state => ({
words: state.words.words
});
export default connect(mapStateToProps, { getWords })(Words);
And finally the App component
import React, { Component, Fragment } from 'react';
import Footer from './Layout/Footer/Footer';
import Header from './Layout/Header/Header';
import WordsDashboard from './Content/Words/WordsDashboard';
import { store } from '../store';
import { Provider } from "react-redux";
import { Words } from './Content/Words/Words';
export class App extends Component {
render() {
return (
<Provider store={store}>
<Fragment>
<Header />
React Buddy
<Words />
<Footer />
</Fragment>
</Provider>
)
}
}
export default App;
Your initialState has only words prop, so when mapping it to props you have one extra words level. Try changing it to:
const mapStateToProps = state => ({
words: state.words
});
Also you need to use mapDispatchToProps for getWords, since in your current code you're missing dispatch wrapper:
const mapDispatchToProps = dispatch => ({
getWords: () => dispatch(getWords())
})
export default connect(mapStateToProps, mapDispatchToProps)(Words);

the state of redux store is changed but mapStateToProps is not working

I checked the state of redux store is changed, but mapStateToProps is not working.
Here is my file tree and code. What I want is that when I get the data from REST API by axios then I dispatches the data to redux-store and update the state of redux-store. After this, I finally get the state of redux-store as like this.props.data
index.js
MainPage.js
- PageHeader.js
- AlarmContentList.js
MainPage.js
import React, {Component} from 'react'
import {connect, Provider} from 'react-redux'
import store from '../../store'
import ReactDOM from 'react-dom'
import axios from 'axios'
import * as AlarmContentActions from '../../store/modules/AlarmContent'
import PageHeader from './PageHeader'
class MainPage extends Component {
constructor(props) {
super(props)
axios.get("http://127.0.0.1:8000/api/main")
.then(res => {
this.setState({
AnswerPostMultiList: res.data,
})
}
)
.catch(err => {
console.log(err)
})
}
state = {
AnswerPostMultiList : [
],
}
render() {
this.props._getInBox(this.state.AnswerPostMultiList)
return(
<>
<PageHeader />
</>
)
}
}
MainPage.defaultProps = {
}
const mapDispatchToProps = (dispatch) => ({
_getInBox: (inBoxList) => {
dispatch(AlarmContentActions.inBox(inBoxList))
}
})
export default connect(null, mapDispatchToProps)(MainPage)
PageHeader.js
import React, {Component} from 'react'
import ReactDOM from 'react-dom'
import './PageHeader.css'
import AlarmContentList from './AlarmContent/AlarmConentList'
class PageHeader extends Component {
render() {
return (
<>
<AlarmContentList />
</>
)
}
}
export default PageHeader
AlarmContentList.js
import React, {Component} from 'react'
import {connect} from 'react-redux'
class AlarmContentList extends Component {
render() {
console.log(this.props, 'this.props')
return (
<>
<div>{this.props.inBox}<div>
</>
)
}
}
AlarmContentList.defaultProps = {
inBox: []
}
const mapStateToProps = (state) => ({
inBox : state.inBox
})
export default connect(mapStateToProps)(AlarmContentList);
index.js
import React, {Component} from 'react'
import {connect, Provider} from 'react-redux'
import store from '../../store'
import ReactDOM from 'react-dom'
import MainPage from './MainPage'
ReactDOM.render(
<Provider store={store}>
<MainPage />
</Provider>, document.getElementById('main-page'))
AlarmContent.js (redux-store)
import {createAction, handleActions} from 'redux-actions'
//define action types
const INBOX = 'AlarmContent/INBOX';
//CREATE action
export const inBox = createAction(INBOX);
// SET initialState
const initialState = {
inBox:[
]
}
// CREATE reducers
export default handleActions({
[INBOX] : (state, action) => {
return {
...state,
inBox : action.payload
}
},
}, initialState)
By checking redux-dev-tool, the procedure that I dispatch data and change state of redux store goes well, isn't it?
Even though state of redux-store is updated, why props from redux-store isn't changed??
(this result of image comes from console.log(this.props, 'this.props') at AlarmContentList.js)

Connected component not receiving store props n Redux

I was doing a bit of refactoring and tried connecting a higher level component to redux using connect() but the component I'm connecting keeps giving me empty props.
I've included the relevant code, I've structured my redux reducers into a ducks format, so the actions/creators and reducers are in one module file.
The files are containers/login.js, presentation/login.js, presentation/logins.js, app.js and the root index.js.
When I decided to rename some actions, files and reducers, moved the connect to a higher component, the connection stopped working and now I have empty props.
Help much appreciated.
// containers/login.js
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom'
import { fetchPage } from '../redux/modules/Login';
import Login from '../presentation/Login';
const mapStateToProps = (state) => {
return {
page: state.page,
forms: state.forms
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchPage: () => dispatch(fetchPage())
} // here we're mapping actions to props
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login);
// redux/modules/login.js
import fetch from 'cross-fetch';
const RECIEVE_FORM = 'RECIEVE_FORM';
export const receiveForm = (response) => ({
type: RECIEVE_FORM,
forms: response.forms
})
const initialState = {
page: "",
forms: []
}
// MIDDLEWARE NETWORK REQUEST DISPATCHER
export const fetchPage = () => {
return dispatch => {
return fetch('http://localhost:3001/login')
.then(
response => response.json(),
)
.then(
response => dispatch(receiveForm(response))
)
}
}
// REDUCER COMPOSITION CALL EXISTING REDUCERS
// REDUCER COMPOSITION PATTERN
// ACCUMULATIVE ACTION REDUCER
export default function Login(state = initialState, action){
switch (action.type){
case RECIEVE_FORM:
return {
...state,
forms: action.forms
}
default:
return state;
}
}
// presentation/login.js
import React, { Component } from 'react';
import styled from 'styled-components';
import Wrapper from '../components/Wrapper';
import Card from '../components/Card';
import Text from '../components/Text';
import Logo from '../components/Logo';
import FormGroup from '../components/FormGroup';
const WrapperLogin = styled(Wrapper)`
.login__card{
padding: 4.5rem 2.5rem 2rem 2.5rem;
}
`;
const BoxLogo = styled.div`
.login__logo{
display: block;
margin: 0 auto;
}
`;
export default class Login extends Component{
componentDidMount() {
console.log(this.props)
//this.props.fetchPage();
}
render(){
return(
<main>
<WrapperLogin className="login">
<Card className="login__card">
<BoxLogo>
<Logo className="login__logo" width={187.36} height={76.77} />
</BoxLogo>
<FormGroup name="login" className="login_formGroup" />
</Card>
<Text primitive="p" margin='4px 0 0 0' size="0.8rem" textAlign="center" display='block'>Brought to you by WORLDCHEFS</Text>
</WrapperLogin>
</main>
)
}
}
// app.js
// manage routes here
//import _ from 'lodash';
import React, { Component } from 'react'
import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';
import Login from './presentation/Login';
type Props = {
}
type State = {
mode: string
};
export default class App extends Component <Props, State> {
constructor(){
super();
this.state = {
...this.state,
mode: 'mobile'
}
}
render(){
return(
<ThemeProvider theme={{ mode: this.state.mode }}>
<Login />
</ThemeProvider>
)
}
}
// root
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './redux/configureStore';
import registerServiceWorker from './registerServiceWorker';
import App from './App';
import { injectGlobal } from 'styled-components';
import styles from './assets/styles';
const store = configureStore();
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root')
);
The reason your props in Login component are empty is because you are not actually using the connected Login container, As you have mentions its in containers/login
So in your App.js change the import of login from ./presentation/login to
import Login from '/path/to/containers/Login';
You have imported presentation component in your app.js rather than container component. Please import your container component like below
import Login from './containers/login.js';
This will solve the problem as per my understanding from your code

How to get a resolved promise to my component with Redux Promise?

I'm making a request in my action - pulling from an API that needs to load in some data into my component. I have it start that request when the component will mount, but I can't seem to get Redux-Promise to work correctly because it just keeps returning:
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
in my dev tools when I try to console.log the value inside of my componentWillMount method.
Here's my code below:
Store & Router
import React from 'react';
import { render } from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import promiseMiddleware from 'redux-promise';
import { Provider } from 'react-redux';
import { Router, hashHistory } from 'react-router';
import routes from './routes';
import rootReducer from './reducers';
const store = createStore(
rootReducer,
applyMiddleware(promiseMiddleware)
);
render(
<Provider store={store}>
<Router history={hashHistory} routes={routes} />
</Provider>,
document.getElementById('root')
);
Action
import axios from 'axios';
export const FETCH_REVIEWS = 'FETCH_REVIEWS';
export const REQUEST_URL = 'http://www.example.com/api';
export function fetchReviews() {
const request = axios.get(REQUEST_URL);
return {
type: FETCH_REVIEWS,
payload: request
};
};
Reviews Reducer
import { FETCH_REVIEWS } from '../actions/reviewActions';
const INITIAL_STATE = {
all: []
};
export default function reviewsReducer(state = INITIAL_STATE, action) {
switch(action.type) {
case FETCH_REVIEWS:
return {
...state,
all: action.payload.data
}
default:
return state;
}
}
Root Reducer
import { combineReducers } from 'redux';
import reviewsReducer from './reviewsReducer';
const rootReducer = combineReducers({
reviews: reviewsReducer
});
export default rootReducer;
Component
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchReviews } from '../../actions/reviewActions';
class Home extends Component {
componentWillMount() {
console.log(this.props.fetchReviews());
}
render() {
return (
<div>List of Reviews will appear below:</div>
);
}
}
export default connect(null, { fetchReviews })(Home);
Any and all help is greatly appreciated. Thank you.
Redux-promise returns a proper Promise object, so you may change your code a little bit to avoid immediate execution.
class Home extends Component {
componentWillMount() {
this.props.fetchReviews().then((whatever) => { console.log('resolved')})
}
// ...
}

Resources