Hi,
I am having trouble with undefined state in mapStateToProps in React Redux and I can’t put my finger on what the problem is. I have passed state into mapStateToProps, but if I then try to map a property of state to a property in mapStateToProps, it gives me “Uncaught TypeError: Cannot read property ‘reduxText’ of undefined at mapStateToProps”. However, if I use store.getState in mapStateToProps, it works perfectly, but I know I shouldn’t be doing this. Could anyone please advise on what I’m doing wrong here? I feel like there’s something crucial that I’m missing but I just can’t figure it out.
Thanks a lot!
const quoteArr=[
['I destroy my enemies when I make them my friends', 'Abraham Lincoln'],
['Don’t live the same year 75 times and call it a life', 'Robin Sharma'],
['Genius is 1% inspiration, 99% perspiration', 'Thomas Edison'],
['Numbing the pain for a while will only make it worse when you finally feel it', 'Albus Dumbledore'],
['Instead of wondering when your next vacation is, maybe you should set up a life you don’t need to escape from', 'Seth Godin'],
['Spread love wherever you go. Let no one ever come to you without leaving happier', 'Mother Teresa'],
['When you reach the end of your rope, tie a knot in it and hang on', 'Franklin D. Roosevelt'],
['The only impossible journey is the one you never begin', 'Tony Robbins'],
['Do not let making a living prevent you from making a life', 'John Wooden'],
['It is better to fail in originality than to succeed in imitation', 'Herman Melville']
];
const colorArr=['blue', 'purple', 'pink', 'red', 'orange', 'yellow', 'green', 'cyan'];
let quoteRandomIndex=Math.floor(Math.random()*10);
let initialColorRandomIndex=Math.floor(Math.random()*8);
let colorRandomIndex=Math.floor(Math.random()*8);
//Redux
//Redux actions
const CHANGE_QUOTE_ACTION='CHANGE_QUOTE_ACTION';
const CHANGE_QUOTE_TRANSITION='CHANGE_QUOTE_TRANSITION';
//Redux action creators
const changeQuoteActionCreator=()=>{
return {
type: CHANGE_QUOTE_ACTION,
payload: {
reduxText: quoteArr[quoteRandomIndex][0],
reduxAuthor: quoteArr[quoteRandomIndex][1],
reduxTweetURL: 'https://twitter.com/intent/tweet?text=\"'+quoteArr[quoteRandomIndex][0]+'\" '+quoteArr[quoteRandomIndex][1],
reduxTextFade: 'textVisible '
}
}
}
const changeQuoteTransitionActionCreator=()=>{
while(quoteArr[quoteRandomIndex][0]==store.getState().reduxText) {
quoteRandomIndex=Math.floor(Math.random()*10);
}
while('container-fluid '+colorArr[colorRandomIndex]+'-color'==store.getState().reduxBackgroundColor) {
colorRandomIndex=Math.floor(Math.random()*8);
};
return {
type: CHANGE_QUOTE_TRANSITION,
payload: {
reduxBackgroundColor: 'container-fluid '+colorArr[colorRandomIndex]+'-color',
reduxButtonColor: 'btn btn-outline shadow-none text-white ' +colorArr[colorRandomIndex]+'-color '+colorArr[colorRandomIndex]+'-hoverColor',
reduxTextColor: colorArr[colorRandomIndex]+'-textColor',
reduxTextFade: 'textInvisible'
}
}
}
const asyncChangeQuoteActionCreator=()=>{
return function(dispatch) {
dispatch(changeQuoteTransitionActionCreator());
setTimeout(function() {
dispatch(changeQuoteActionCreator());
}, 1000);
};
}
//Initial Redux state
initialReduxState={
reduxText: '',
reduxAuthor: '',
reduxBackgroundColor: 'container-fluid '+colorArr[initialColorRandomIndex]+'-color',
reduxButtonColor: 'btn btn-outline shadow-none text-white ' +colorArr[initialColorRandomIndex]+'-color '+colorArr[initialColorRandomIndex]+'-hoverColor',
reduxTextColor: colorArr[initialColorRandomIndex]+'-textColor',
reduxTweetURL: ''
}
//Redux reducer
const changeQuoteReducer=(state=initialReduxState, action)=>{
console.log(state);
switch (action.type) {
case CHANGE_QUOTE_ACTION:
return Object.assign({}, state, {reduxText: action.payload.reduxText, reduxAuthor: action.payload.reduxAuthor, reduxTweetURL: action.payload.reduxTweetURL, reduxTextFade: action.payload.reduxTextFade});
case CHANGE_QUOTE_TRANSITION:
return Object.assign({}, state, {reduxBackgroundColor: action.payload.reduxBackgroundColor, reduxButtonColor: action.payload.reduxButtonColor, reduxTextColor: action.payload.reduxTextColor, reduxTextFade: action.payload.reduxTextFade})
default:
return state;
}
}
//Redux store (including Thunk)
const store=Redux.createStore(
changeQuoteReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
//Redux Provider
const Provider=ReactRedux.Provider;
//Redux connect
const connect=ReactRedux.connect;
//React
class Presentational extends React.Component {
constructor(props) {
super(props);
this.changeQuote=this.changeQuote.bind(this);
}
changeQuote() {
this.props.changeQuoteDispatch();
}
componentDidMount() {
setTimeout(()=>{
this.props.changeQuoteDispatch();
}, 500);
}
render() {
return (
<div class={this.props.backgroundColor} id='background' style={{position: 'fixed', height: '100%'}}>
<div class='d-flex align-items-center justify-content-center' id='quote-box-flexbox-wrapper' style={{height: '100%'}}>
<div class={this.props.textColor} id='quote-box' style={{backgroundColor: 'white', width: '550px'}}>
<div class='d-flex flex-column' id='quote-box-content-flexbox-wrapper'>
<TextComponent text={this.props.text} textFade={this.props.textFade}/>
<AuthorComponent author={this.props.author} textFade={this.props.textFade}/>
<div class='d-flex justify-content-between' id='buttons-flexbox-wrapper'>
<NewQuoteComponent changeQuote={this.changeQuote} backgroundColor={this.props.backgroundColor} buttonColor={this.props.buttonColor}/>
<TweetQuoteComponent tweetURL={this.props.tweetURL} buttonColor={this.props.buttonColor}/>
</div>
</div>
</div>
</div>
</div>
);
}
}
class TextComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<p class={this.props.textFade} id='text' style={{textAlign: 'center', lineHeight: '1'}}><span class='quoteMark' style={{fontFamily: 'RocknRoll One'}}>“</span>{this.props.text}</p>
);
}
}
class AuthorComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<p class={this.props.textFade} id='author'>{this.props.author}</p>
);
}
}
class NewQuoteComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<button type='button' class={this.props.buttonColor} id='new-quote' onClick={this.props.changeQuote}>New quote</button>
);
}
}
class TweetQuoteComponent extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<a href={this.props.tweetURL} class={this.props.buttonColor} id='tweet-quote' target='_top'><img src='https://i.imgur.com/dRBtqhv.png' style={{width: 30}}/></a>
);
}
}
//Redux
//Map state to props
const mapStateToProps=(state)=>{
tempState=store.getState(); //Why do I have to do this?
return {
text: tempState.reduxText,
author: tempState.author,
backgroundColor: tempState.reduxBackgroundColor,
buttonColor: tempState.reduxButtonColor,
textColor: tempState.reduxTextColor,
tweetURL: tempState.reduxTweetURL,
textFade: tempState.reduxTextFade
}
}
//Map dispatch to props
const mapDispatchToProps=(dispatch)=>{
return {
changeQuoteDispatch: ()=>{
dispatch(asyncChangeQuoteActionCreator())
}
}
}
//Subscribe to the store
store.subscribe(mapStateToProps);
//Dispatch to the store
store.dispatch(mapDispatchToProps);
//Connect Redux to React
const Container=connect(mapStateToProps, mapDispatchToProps)(Presentational);
//Redux Provider
class AppWrapper extends React.Component {
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
}
ReactDOM.render(<AppWrapper/>, document.getElementById('random-quote-machine-node'));