Getting undefined when accessing redux stores state property in react App - reactjs

I am using redux in my react app and I am getting undefined when I access redux state property in one of my component, why is that? the state is valid when I call console.log in reducer file : here is my reducerFile :
const initState = {
isCurrentUser : true
}
export default function(state=initState, action) {
console.log(`this is from localAuthReducer ${state.isCurrentUser}`)
switch(action.type) {
default:
return state
}
}
Here is my react component :
import React, {Component} from 'react';
import styles from './IndexPage.module.scss';
import { connect } from 'react-redux';
import Header from './../../components/Header/Header';
class IndexPage extends Component {
render() {
return(
<div className={styles.container}>
<Header
isCurrentUser = {this.props.isCurrentUser}
/>
{ console.log(`this is from indexPage ${this.props.isCurrentUser}`)}
</div>
);
}
}
function mapStateToProps(state) {
return {
isCurrentUser : state.isCurrentUser
}
}
export default connect(mapStateToProps, null)(IndexPage);
Here is my index.js file :
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App/App';
import {Provider } from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import reducers from './reducers/index';
import reduxThunk from 'redux-thunk';
const store = createStore(
reducers,
applyMiddleware(reduxThunk)
);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.querySelector("#root"));
I dont know where I am going wrong isCurrentUser must have value of true as it is the default value of the redux state

Related

Fetching data in other components with react hook

Im new to react hooks and are experimenting a bit. I can display my values that are generated in Provider.js in App.js through Comptest.js. My problem is that the structure of my project with css etc makes it inconvenient to have a structure in the App.js like this:
<Provider>
<Comptest />
</Provider>
is it possible to fetch the data without displaying the components in that way in the app? just passing it between the components.
Here is a compact version of my application:
App.js
import React, { useContext } from "react";
import Provider from "./Provider";
import Comptest from "./Comptest";
import DataContext from "./Context";
function App() {
return (
<div className="App">
<h2>My array!</h2>
<Provider>
<Comptest />
</Provider>
</div>
);
}
export default App;
Provider.js
import React, { useState } from "react";
import DataContext from "./Context";
const Provider = props => {
const data = ["item1", "item2"];
return (
<DataContext.Provider value={data}>{props.children}</DataContext.Provider>
);
};
export default Provider;
Comptest.js
import React from "react";
import DataContext from "./Context";
const Comptest = () => {
const content = React.useContext(DataContext);
console.log(content);
return <div>{(content)}</div>;
};
export default Comptest;
Context.js
import React from "react";
const DataContext = React.createContext([]);
export default DataContext;

How to Pass in Store as a prop

I am currently having a problem getting store to be passed in as a prop and am wondering what to label a few things.
The current error is within create store, I'm unsure what to do with it.
I have tried other methods and only want to use the store method where I pass it in as a prop
import React from 'react';
import { MockGit } from './Constants';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import Button from '#material-ui/core/Button';
import TestAPI from './TestAPI';
import { displayGitData, userInfoURL, getDataSaga } from '../sagas/sagas';
import { createStore } from 'redux';
class GitData extends React.Component {
constructor(props) {
super(props);
}
render() {
const store = createStore(...); //this is what im unsure of.
const { store } = this.props;
return (
<ExpansionPanel>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography> {MockGit} </Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
{displayGitData()}
{userInfoURL()}
{getDataSaga()}
<TestAPI />
</ExpansionPanelDetails>
</ExpansionPanel>
);
}
}
export default GitData;
The goal is to get store passed in as a prop with no errors.
Any help would be great, Thanks!
You're doing it wrong, here's the recommended way to use React with Redux:
store.js
import { createStore } from 'redux';
export default createStore(...)
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store.js'
const App = () => (<h1>Hello from App</h1>);
ReactDOM.render(
<Provider store={store}><App/></Provider>
document.querySelector('#react-root')
);
You now have an app that is bound with the store.
The react-redux npm package allows also to bind component props to store dispatches and store state, example:
my-component.js
import React from 'react';
import { connect } from 'react-redux';
class MyComponent extends React.Component {
render() {
return (
<p>{this.props.hello}</p>
)
}
}
export default connect(state => ({hello: state.helloReducer.value}))(MyComponent)
For further tutorials, check the official docs of react-redux, or this good youtube playlist.

MuiThemeProvider: How to use different themes for different routes?

I need to slightly change the theme depending on the current section of the site.
It seems that MuiThemeProvider only sets muiTheme on load; but it needs to be updated when the props change.
How can this be done?
You can try to put the theme in a wrapping component that keeps the theme in it's state. Using React's context this component exposes a function to child components to change the state.
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import PropTypes from 'prop-types';
import theme from './theme';
import themeOther from './theme-other'
class Wrapper extends Component {
static childContextTypes = {
changeTheme: PropTypes.func
};
constructor(props) {
super(props);
this.state = {
muiTheme: getMuiTheme(theme)
};
}
getChildContext() {
return {changeTheme: this.changeTheme};
}
changeTheme = () => {
this.setState({
muiTheme: getMuiTheme(themeOther)
})
};
render() {
return (
<MuiThemeProvider muiTheme={this.state.muiTheme}>
{this.props.children}
</MuiThemeProvider>
)
}
}
export default Wrapper;
In some child component you can access the context and call the changeTheme function to set a different theme in the state. Make sure to include contextTypes else you can't access the function.
import React, { Component } from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import PropTypes from 'prop-types'
class ChildComponent extends Component {
static contextTypes = {
changeTheme: PropTypes.func
};
render() {
return (
<RaisedButton
primary
onTouchTap={this.context.changeTheme}
label="Change The Theme"
/>
);
}
}
export default ChildComponent;
In the root of your app just render the wrapper.
ReactDOM.render(
<Wrapper>
<App />
</Wrapper>,
document.getElementById('root')
);
EDIT:
My first solution might have been abit too much. Since you are replacing the whole theme for the whole app. You can also use the MuiThemeProvider down the tree like so.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
import inject from 'react-tap-event-plugin';
inject();
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import theme from './theme';
ReactDOM.render(
<MuiThemeProvider muiTheme={getMuiTheme(theme)}>
<App />
</MuiThemeProvider>,
document.getElementById('root')
);
In a child component you can just use the MuiThemeProvider again and override some properties. Note that these changes will reflect on all the children inside this MuiThemeProvider.
import React, { Component } from 'react';
import RaisedButton from 'material-ui/RaisedButton';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import theme from './theme';
import { green800, green900 } from 'material-ui/styles/colors';
const localTheme = getMuiTheme(Object.assign({}, theme, {
palette: {
primary1Color: green800,
primary2Color: green900
}
}));
class App extends Component {
render() {
return (
<div>
<RaisedButton
primary
label="Click"
/>
<MuiThemeProvider muiTheme={localTheme}>
<RaisedButton
primary
label="This button is now green"
/>
</MuiThemeProvider>
</div>
);
}
}
export default App;

React + Redux: Cannot read property 'props' of null error

I have been receiving a Cannot read property 'props' of null error in th client app that I am currently building with react and redux.
I have been trying to implement a wrapper component/container for other react components in a web app as follows.(The reason I have included the contents of 4 files is that I don't know where the error is originating from)
main.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
import store, {history} from './App/store';
import Init from './App/Init';
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<Router path="/" component={Init}>
<IndexRoute component={Container}/>
<Route path="/view/:ItemId" component={Single}></Route>
</Router>
</Router>
</Provider>,
document.getElementById('main')
);
class Container extends Component{
render(){
return(
<div>hello</div>
);
}
}
class Single extends Component{
render(){
return(
<div>hello</div>
);
}
}
Init.js
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux';
import * as actionCreators from './ActionCreators'
import App from './App';
function mapStateToProps(state, ownProps){
return{
items: state.items,
entities: state.entities,
};
}
function mapDispatchToProps(dispatch){
return bindActionCreators(actionCreators, dispatch);
}
const Init = connect(mapStateToProps, mapDispatchToProps)(App);
export default Init;
store.js
import { createStore, compse, applyMiddleware } from 'redux';
import { browserHistory } from 'react-router';
import thunkMiddleware from 'redux-thunk';
import {syncHistoryWithStore} from 'react-router-redux';
//import the root reducer
import rootReducer from './rootReducer';
//import data
import {entities} from '../../data/entities';
import {items} from '../../data/items';
//create an object for the default data
const defaultState = {
items,
entities,
};
const store = createStore(rootReducer, defaultState);
export const history = syncHistoryWithStore(browserHistory, store);
export default store;
and App.js
import React, {Component} from 'react';
export default class App extends Component {
render(){
return(
<div>
<div className="content-wrapper">
<div className="grid-page">
{React.cloneElement({...this.props}.children, {...this.props})}//The error occurs here
</div>
</div>
</div>
);
}
}
and here is the console log of the error
ReactElement.js:271 Uncaught TypeError: Cannot read property 'props' of null
at Object.ReactElement.cloneElement (ReactElement.js:271)
at Object.cloneElement (ReactElementValidator.js:223)
at App.render (App.js:15)
at App.<anonymous> (makeAssimilatePrototype.js:15)
at ReactCompositeComponent.js:796
at measureLifeCyclePerf (ReactCompositeComponent.js:75)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (ReactCompositeComponent.js:795)
at ReactCompositeComponentWrapper._renderValidatedComponent (ReactCompositeComponent.js:822)
at ReactCompositeComponentWrapper.performInitialMount (ReactCompositeComponent.js:362)
at ReactCompositeComponentWrapper.mountComponent (ReactCompositeComponent.js:258)
Please excuse the lack of brevity in my question, I have not found any answers on stack overflow that address the issue I am having, but if you could shed some light on what is going wrong, that would be great.
Thanks
class definitions in the spec don't get hoisted, though Babel is compiling it down to a function expression, which will hoist the variable, which is why the code doesn't crash at runtime, but the class definitions are still undefined
putting your class Container and class Single above your call to ReactDOM.render should solve this issue.

React with Redux - unable to bind action to parent

I am new to the Redux pattern i'm having some trouble linking an action in a separate JS file to it's parent component. Here is the component:
import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import playSample from './sampleActions/clickToPlay';
class SamplesInnerLrg extends Component {
render() {
return <div>
{
this.props.samples.map((sample) => {
return (
<div key={sample.id} className="sample-comp-lge">
<div className="sample-comp-lge-header">
<span className="sample-comp-lge-Name">{sample.sampleName}</span>
<span className="sample-comp-lge-id">{sample.sampleFamily}</span>
</div>
<div className="sample-comp-lge-audio" ref={sample.id} onClick={() => this.bind.playSample(sample)}>
<audio preload="auto" id="myAudio">
<source src={sample.soundSource} type="audio/wav" />
</audio>
</div>
<div className="sample-comp-lge-owner">{sample.uploader}</div>
</div>
)
})
}
</div>
}
}
function mapStateToProps(state) {
return {
samples:state.samples
};
}
function matchDispatchToProps(dispatch) {
return bindActionCreators({playSample:playSample},dispatch)
}
export default connect(mapStateToProps,matchDispatchToProps)(SamplesInnerLrg);
Specifically I am trying to have an onClick action on this line that will call a function in an imported file (clickToPlay.js):
<div className="sample-comp-lge-audio" ref={sample.id} onClick={() => this.bind.playSample(sample)}>
The clickToPlay file looks like so:
import $ from 'jquery';
export const playSample = (sample) => {
console.log(sample);
return {
type:"Play_Sample_clicked",
payload:sample
}
};
the error i'm getting on click is Cannot read property 'playSample' of undefined. I'm guessing I have bound the action to the component correcly but I can't tell why?
EDIT:
Here is my index.js file as requested:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import {Provider} from 'react-redux';
import { createStore,compose } from 'redux';
import allReducers from './reducers';
const store = createStore(allReducers,compose(
window.devToolsExtension ? window.devToolsExtension() : f => f
));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
,
document.getElementById('root')
);
You aren't exporting 'playSample' as the default export, you have two ways to reslove this:
You can do:
import { playSample } from './sampleActions/clickToPlay';
or
you can change export const playSample to const playSample Then add export default playSample at the end of your file.
Another note I want to mention about this line:
return bindActionCreators({playSample:playSample},dispatch)
I don't see why you are doing {playSample:playSample} just change it to playSample. ES6 allows you to eliminate key if it's the same as value, this is called object literal property value shorthand.

Resources