What's wrong in the below react redux code snippets? - reactjs

I have created react app and try to run after adding simple redux stuffs as below.
Initial state value and updated state value(after button click) not appearing in the screen.
No error thrown in the console.
Expected result should be display the initial Message from store as "Please subscribe".
After clicking subscribe button, the text should be change into "Thanks for Subscribing!".
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux';
import reducer from './Reducer';
import { Provider } from 'react-redux';
const store = createStore(reducer);
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
reportWebVitals();
Reducer.js
const initialState = {
message: "Please subscribe!"
};
const reducer = (state = initialState, action) => {
console.log(action);
const newState = { ...state };
if (action.type === "PRINT_ITEM") {
newState.message = "Thanks for subscribing!"
};
return newState;
}
export default reducer;
App.js
import { Component } from 'react';
import './App.css';
import { NewComp } from './NewComp';
class App extends Component {
render() {
return (
<div className="App">
<h1>Welcome</h1>
<NewComp />
</div>
);
}
}
export default App;
NewComp.js
import React, { Component } from 'react'
import { connect } from 'react-redux';
export class NewComp extends Component {
styles = {
fontStyle: 'italic',
color: 'purple'
}
render() {
return (
<div className="App">
<h3 style={this.styles}>{this.props.msg}</h3>
<button onClick={this.props.ButtonChange}>Subscribe</button>
</div>
);
}
}
const mapStateToProps = (state) => {
console.log(state); //Not get fired
return {
msg: state.message
};
};
const mapDispatchToProps = (dispatch) => {
console.log(dispatch); //Not get fired
return {
ButtonChange: () => dispatch({ type: "PRINT_ITEM" })
};
};
export default connect(mapStateToProps, mapDispatchToProps)(NewComp);

In App.js, you're importing the named export from NewComp, which is not the Redux-connected version. Instead, import the default export, which is Redux-connected:
import NewComp from './NewComp';

Related

React Component cant acces Redux store

I have the following modules for my React app:
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import MainApp from './MainApp';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<MainApp />
</React.StrictMode>,
document.getElementById('root')
);
MainApp.js
import React from 'react';
import App from './containers/app';
import './App.css';
import {ConnectedRouter} from 'connected-react-router'
import {Provider} from 'react-redux';
import {Route, Switch} from 'react-router-dom';
import configureStore, {history} from './store';
export const store = configureStore();
const MainApp = () =>
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route path="/" component={App}/>
</Switch>
</ConnectedRouter>
</Provider>;
export default App;
store/index.js
import {applyMiddleware, compose, createStore} from 'redux';
import reducers from '../reducers/index';
import {createBrowserHistory} from 'history'
import {routerMiddleware} from 'connected-react-router';
import createSagaMiddleware from 'redux-saga';
import rootSaga from '../sagas/index';
const history = createBrowserHistory();
const routeMiddleware = routerMiddleware(history);
const sagaMiddleware = createSagaMiddleware();
const middlewares = [sagaMiddleware, routeMiddleware];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(initialState) {
const store = createStore(reducers(history), initialState,
composeEnhancers(applyMiddleware(...middlewares)));
sagaMiddleware.run(rootSaga);
if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers/index', () => {
const nextRootReducer = require('../reducers/index');
store.replaceReducer(nextRootReducer);
});
}
return store;
}
export {history};
containers/dataviewer/index.js
import React from 'react';
import {connect} from 'react-redux';
import {
connectPath
} from '../../actions/Paths';
import Button from '#material-ui/core/Button';
import ButtonGroup from '#material-ui/core/ButtonGroup';
import TabularViewer from './TabularViewer';
import CollapsableViewer from './CollapsableViewer';
import ChartViewer from './ChartViewer';
class DataViewer extends React.Component {
constructor() {
super();
this.state = {
displayStyle: null
}
this.handleClick = this.handleClick.bind(this);
}
handleClick = (style) => {
this.setState({displayStyle: style})
}
DisplayControllers = () => {
return (
<ButtonGroup variant="text" color="primary" aria-label="outlined primary button group">
<Button color={this.state.displayStyle === 'tabular'? 'secondary': 'primary'} onClick={() => this.handleClick('tabular')}>Tabular</Button>
<Button color={this.state.displayStyle === 'collapsable'? 'secondary': 'primary'}onClick={() => this.handleClick('collapsable')}>Colapsable</Button>
<Button color={this.state.displayStyle === 'chart'? 'secondary': 'primary'} onClick={() => this.handleClick('chart')}>Gráfico</Button>
</ButtonGroup>
)
}
DisplayComponent = () => {
switch (this.state.displayStyle) {
case 'tabular':
return <TabularViewer />
case 'collapsable':
return <CollapsableViewer />
case 'chart':
return <ChartViewer />
default:
return <p>Seleccione un estilo de desplegado.</p>;
}
}
render() {
return (
<div>
<p>Data Viewer</p>
<this.DisplayControllers />
<this.DisplayComponent />
</div>
)
}
}
const mapStateToProps = ({paths}) => {
const {connection, path, data} = paths;
return {
connection,
path,
data
}
}
export default connect(mapStateToProps, {connectPath})(DataViewer)
Te problem is that I get the following error when the component is mounted:
Error: Could not find "store" in the context of "Connect(DataViewer)". Either wrap the root component in a <Provider>, or pass a custom React context provider to <Provider> and the corresponding React context consumer to Connect(DataViewer) in connect options.
I can't see what I am missing.
EDIT
containers/app.js
import React from 'react';
import DataViewer from './DataViewer';
class App extends React.Component {
render() {
return (
<div className="App">
<header className="App-header">
<DataViewer
database_host="127.0.0.1'"
database_port="5432"
database_name="TCDigital"
database_user="postgres"
database_password="xxxx"
path="Ventas"
displayStyle="collapsable"
/>
</header>
</div>
);
}
}
export default App;

React/TypeScript/Redux/Thunk reducer gets triggered but state is not updated in redux store

I am trying to populate my redux store state with a list of genres from an API, I can get the action to dispatch to the reducer, but the reducer does not seem to update the state because my console.log in src/components/MovieForm.tsx returns the default state of "null" instead of the array of genres and I do not know why, I am trying to see if the state is updated in src/components/MovieForm.tsx in the setInterval where I am logging the state, maybe the problem is how I am accessing the state? Here are the files:
src/actions/movieActions.ts:
import { ActionCreator, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { IMovieState } from '../reducers/movieReducer';
import axios from 'axios';
export enum MovieActionTypes {
ANY = 'ANY',
GENRE = 'GENRE',
}
export interface IMovieGenreAction {
type: MovieActionTypes.GENRE;
genres: any;
}
export type MovieActions = IMovieGenreAction;
/*<Promise<Return Type>, State Interface, Type of Param, Type of Action> */
export const movieAction: ActionCreator<ThunkAction<Promise<any>, IMovieState, void, IMovieGenreAction>> = () => {
return async (dispatch: Dispatch) => {
try {
console.log('movieActions called')
let res = await axios.get(`https://api.themoviedb.org/3/genre/movie/list?api_key=${process.env.REACT_APP_MOVIE_API_KEY}&language=en-US`)
console.log(res.data.genres)
dispatch({
genres: res.data.genres,
type: MovieActionTypes.GENRE
})
} catch (err) {
console.log(err);
}
}
};
src/reducers/movieReducer.ts:
import { Reducer } from 'redux';
import { MovieActionTypes, MovieActions } from '../actions/movieActions';
export interface IMovieState {
//property: any;
genres: any;
}
const initialMovieState: IMovieState = {
//property: null,
genres: null,
};
export const movieReducer: Reducer<IMovieState, MovieActions> = (
state = initialMovieState,
action
) => {
switch (action.type) {
case MovieActionTypes.GENRE: {
console.log('MovieActionTypes.GENRE called')
return {
genres: action.genres,
};
}
default:
console.log('Default action called')
return state;
}
};
src/store/store.ts:
import { applyMiddleware, combineReducers, createStore, Store } from 'redux';
import thunk from 'redux-thunk';
import { IMovieState, movieReducer } from '../reducers/movieReducer';
// Create an interface for the application state
export interface IAppState {
movieState: IMovieState
}
// Create the root reducer
const rootReducer = combineReducers<IAppState>({
movieState: movieReducer
});
// Create a configure store function of type `IAppState`
export default function configureStore(): Store<IAppState, any> {
const store = createStore(rootReducer, undefined, applyMiddleware(thunk));
return store;
}
src/components/MovieForm.tsx (the file that is supposed to dispatch the action):
import React, { useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Paper from '#material-ui/core/Paper';
import Box from '#material-ui/core/Box';
import Select from '#material-ui/core/Select';
import MenuItem from '#material-ui/core/MenuItem';
import { spacing } from '#material-ui/system';
import Card from '#material-ui/core/Card';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import { CardHeader, TextField, CircularProgress } from '#material-ui/core';
import { useDispatch, useSelector } from 'react-redux';
import { movieAction } from '../actions/movieActions';
import { IAppState } from '../store/store';
import axios from 'axios';
const MovieForm = () => {
const dispatch = useDispatch()
const getGenres = () => {
console.log('actions dispatched')
dispatch(movieAction())
}
const genres = useSelector((state: IAppState) => state.movieState.genres);
//const [genreChoice, setGenreChoice] = useState('')
return (
<>
<h1>Movie Suggester</h1>
<Paper elevation={3}>
<Box p={10}>
<Card>
<div>Hello World. </div>
<Select onChange={() => console.log(genres)}>
<MenuItem>
hello
</MenuItem>
<br />
<br />
</Select>
<Button onClick={() => {
getGenres()
setTimeout(function(){
console.log(genres)
}, 5000)
}}>genres list</Button>
<Button onClick={() => console.log(axios.get(`https://api.themoviedb.org/3/discover/movie?api_key=${process.env.REACT_APP_MOVIE_API_KEY}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&with_genres=35&page=1`))}>Click me</Button>
</Card>
</Box>
</Paper>
</>
)
}
export default MovieForm
and here is the src/index.tsx in case the problem is here and I'm unaware:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom';
import './index.css';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/core/styles';
import theme from './theme';
import App from './App';
import configureStore from './store/store';
const store = configureStore();
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<Router>
<App />
</Router>
</ThemeProvider>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
Thanks for taking a look at this and and attempting to help me see what I am unable to!

How to solve "Invalid Hook Call"?

I am learning react-redux, I couldn't understand what problem occuring when I wrap App component with Provider.
Error: Invalid Hook Call
https://i.stack.imgur.com/yFSnF.png
But If I don't wrap it's OK.
Now, My question is what's the mistake in my code?
Root Component:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './components/App';
import reducers from './reducers';
const store = createStore(reducers);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>
,
document.getElementById('root')
);
App Component:
import React from 'react';
import SongList from './songList';
const App = ()=>{
return (
<div>
<SongList />
</div>
);
};
export default App;
SongList Component:
import React from 'react';
class SongList extends React.Component{
render(){
return(
<div className='ui divided list'>
<div className='ui header'>
<div className='title'>
Song List
</div>
</div>
<div className='ui button primary'>
Select
</div>
</div>
);
}
};
export default SongList;
Reducers:
import {combineReducers} from 'redux';
const songReducer = ()=>{
return [
{title:'Zikrullah', duration: 4.05},
{title: 'Madina', duration: 5.50},
{title: 'Sunnat', duration: 3.96},
{title: 'Mandatory', duration:5.16}
]
};
const selectedSongReducer = (selectedSong = null, action) => {
if(action.type === 'SONG_SELECTED'){
return action.payload;
}
return selectedSong;
};
export default combineReducers({songs: songReducer,
selectedSong: selectedSongReducer});
Action:
export const selectSong = (song)=> {
return {
type: 'SONG_SELECTED',
payload:song
};
};
I am trying to identify the wrong part of code for two days. I couldn't identify. Please, help me to solve the issue.

How to create multiple instance with `redux` based component?

I am using Redux with my reactjs app. I strucking with 2 doubts here.
I would like to create multiple instace of redux based component
I like to control / show the store data to other component too..
how to achieve the both? any one help me?
I tried like this: got error:
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "./reducer";
import App from "./App";
import Source from "./Source"; //how to get store data here too..
import "./styles.css";
var store = createStore(reducer);
const rootElement = document.getElementById("container");
ReactDOM.render(
<Provider store={store}>
<App />
<App /> //throws error
</Provider>,
rootElement
);
Live Demo
The Provider tag should contain a single React child element. You can overcome this by creating a fake Higher-Order-Component as below:
const Aux = props => props.children;
Please try the below code:
import React from "react";
import ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import reducer from "./reducer";
import App from "./App";
import Source from "./Source";
import "./styles.css";
var store = createStore(reducer);
const Aux = props => props.children;
const rootElement = document.getElementById("container");
ReactDOM.render(
<Provider store={store}>
<Aux>
<App />
<App />
</Aux>
</Provider>,
rootElement
);
You must connect your component at Redux Store like this:
import React, { Component } from "react";
import { connect } from "react-redux";
class Source extends Component {
render() {
const { counter, increaseCount, decreaseCount } = this.props;
return (
<div className="container">
<h1>How to show count here?</h1>
<h2>{counter}</h2>
<button
onClick={() => {
increaseCount();
}}
>
How to increase count?
</button>
</div>
);
}
}
const mapStateToProps = state => ({
counter: state.count
});
var increaseAction = { type: "increase" };
var decreaseAction = { type: "decrease" };
const mapDispatchToProps = dispatch => {
return {
increaseCount: function() {
return dispatch(increaseAction);
},
decreaseCount: function() {
return dispatch(decreaseAction);
}
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Source);

New to react and Redux, why am i getting an undefined store being passed?

I am not sure if I am even setting up this redux-react project correctly. I am confused as to how I can actually start using store within my react app.
When I try to console.log store I am getting undefined. I have gotten most of this from a boilerplate and am unsure of how some of these parts interact. Currently I have an index.js with
import { Provider } from 'react-redux'
import { configureStore } from './store/configureStore';
const store = configureStore()
import { Root} from './containers/Root';
import Home from './containers/Home'
ReactDOM.render(
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={Root}>
<IndexRoute component={Home} />
</Route>
</Router>
</Provider>,
document.getElementById('root')
);
Root.js :
import React, { Component } from 'react';
import DevTools from './DevTools';
import MyNavbar from '../components/MyNavbar';
import Footer from '../components/Footer'
module.exports = class Root extends Component {
render() {
const { store } = this.props;
console.log(store)
return (
<div>
<MyNavbar />
{this.props.children}
<Footer />
{/* Being the dev version of our Root component, we include DevTools below */}
{/*<DevTools />*/}
</div>
);
}
};
Home component:
import React, { Component, PropTypes } from 'react';
import { Row, Col, Grid } from 'react-bootstrap'
import HowItWorks from '../components/HowItWorks'
import GetStarted from '../components/GetStarted'
import Setup from './Setup'
export default class Home extends Component {
render() {
// we can use ES6's object destructuring to effectively 'unpack' our props
return (
<section>
<div className="slider-wrapper">
<GetStarted />
</div>
<Grid>
<div className="howwork-wrapper">
<Row >
<Col md={12}>
<HowItWorks />
</Col>
</Row>
</div>
</Grid>
</section>
);
}
}
configureStore.js :
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from '../reducers';
import createLogger from 'redux-logger';
import thunk from 'redux-thunk';
import DevTools from '../containers/DevTools';
const logger = createLogger();
const finalCreateStore = compose(
applyMiddleware(logger, thunk),
DevTools.instrument()
)(createStore);
module.exports = function configureStore(initialState) {
const store = finalCreateStore(rootReducer, initialState);
if (module.hot) {
module.hot.accept('../reducers', () =>
store.replaceReducer(require('../reducers'))
);
}
return store;
};
reducers/index.js:
import { combineReducers } from 'redux';
import auth from './auth'
const rootReducer = combineReducers({
auth
});
export default rootReducer;
reducers/auth.js:
import { LOGIN, LOGIN_FAIL, LOGOUT } from '../constants/ActionTypes'
export default function auth(state = {}, action) {
switch (action.type) {
case LOGIN:
return state;
case LOGIN_FAIL:
return state ;
case LOGOUT:
return state ;
default:
return state;
}
}
constants/ActionTypes:
export const LOGIN = 'LOGIN';
export const LOGIN_FAIL = 'LOGIN_FAIL';
export const LOGOUT = 'LOGOUT';
You need to connect your components to get access to the store/state. To do this, modify your Root component like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import DevTools from './DevTools';
import MyNavbar from '../components/MyNavbar';
import Footer from '../components/Footer'
class Root extends Component {
render() {
const { state } = this.props;
console.log(state)
return (
<div>
<MyNavbar />
{this.props.children}
<Footer />
{/* Being the dev version of our Root component, we include DevTools below */}
{/*<DevTools />*/}
</div>
);
}
};
const mapStateToProps = (state) => {
return {
state: state
}
}
module.exports = connect(mapStateToProps)(Root);
A few notes, since you are transpiling anyway, you could export instead of module.exports in your declaration. Also, generally you do not want to expose your entire state to a single component. You can connect multiple components (make them "containers") by following this pattern.
The following is an example component connected to your state.
import React, { Component } from 'react';
import { connect } from 'react-redux';
export class SomeComponent extends Component {
render() {
const { someKey, dispatchSomething } = this.props;
return (
<div onClick={dispatchSomething}>
<h1>My rendered someKey variable: {someKey}</h1>
</div>
);
}
};
const mapStateToProps = (state) => {
return {
someKey: state.someReducer.someKey
}
}
const mapDispatchToProps = (dispatch) => {
return {
dispatchSomething: () => dispatch(someActionCreator())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(SomeComponent);
References
react-redux API: connect

Resources