'Redux' is not defined ... as well as ReactRedux and ReactDOM - javascript

I am working through the React/Redux exercise on FreeCodeCamp.org. After finishing the exercise I want to take it a step farther by implementing it on a local host, and then deploying it to github.
So far, I've used npx create-react-app {appname} in node. Replaced, the original app.js file with my own code that I have below and tried to locally host with npm start on Node.
When that didn't work I did some googling and found the following command to install redux npm install redux react-redux redux-thunk --save. when that didn't work I tried adding the fourth line of my code import { createStore } from 'redux';
Currently I am facing the current error
What can I do to get my app to locally host, so I can then move on to the next step of deploying it to Github?
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { createStore } from 'redux';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// Change code below this line
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState({
input: '',
messages: this.state.messages.concat(this.state.input)
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// Change code above this line
const mapStateToProps = (state) => {
return {messages: state}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
};
ReactDOM.render(<AppWrapper/>, document.getElementById("root"))

you didn't import them;
import ReactDOM from 'react-dom';
import Redux from 'redux';
import ReactRedux from 'react-redux';
by the way there is a cleaner way to import what you need. you will need a little refactoring for that:
import {render} from 'react-dom';
import {Provider, createStore} from 'redux';
import {connect} from 'react-redux';
you get the idea, instead of importing the default export, you import selectively and in your code just use the named import instead of default.name
(e.g.
ReactDOM.render(<AppWrapper/>, document.getElementById("root")) becomes
render(<AppWrapper/>, document.getElementById("root"))
Check out this SO answer for further reading

Related

my react code is working but when i refresh the page i get TypeError: Cannot read property 'Location' of undefined

Starting with GamePage, it provides 2 routes which renders the components GameList and GameDetailPage. Both work fine at first but When i refresh the page for Gamelist component, it still rerenders the page but when i refresh the page for GameDetailPage, i get the error TypeError: Cannot read property 'Location' of undefined. I do not understand why it is unable to fetch data from state whenever i refresh.
gamepage.jsx
import React from "react";
import GamesList from "../../components/games-list/game-list.component";
import { Route } from "react-router-dom";
import GameDetailPage from "../gamedetailpage/gamedetailpage.component";
import {firestore,convertCollectionsSnapshotToMap} from '../../firebase/firebase.utils'
import {connect} from 'react-redux'
import {updateFootballGames} from '../../redux/games/games.actions'
class GamePage extends React.Component {
unsubscribeFromSnapshot=null;
//whenever the component mounts the state will be updated with the football games.
componentDidMount(){
const {updateFootballGames}=this.props
const gameRef=firestore.collection('footballgames')
gameRef.onSnapshot(async snapshot=>{
const collectionsMap=convertCollectionsSnapshotToMap(snapshot)
updateFootballGames(collectionsMap)
})
}
render() {
const { match } = this.props;
return (
<div className="game-page">
<h1>games page</h1>
<Route exact path={`${match.path}`} component={GamesList} />
<Route path={`${match.path}/:linkUrl`} component={GameDetailPage}
/>
</div>
);
}
}
const mapStateToProps=state=>({
games:state.games.games
})
const mapDispatchToProps=dispatch=>({
updateFootballGames:collectionsMap=>
dispatch(updateFootballGames(collectionsMap))
})
export default connect(mapStateToProps, mapDispatchToProps)(GamePage);
gamedetailpage.component.jsx
import React from "react";
import { connect } from "react-redux";
import GamePreview from '../../components/game-preview/game-preview.component'
import GameDetails from '../../components/game-details/game-details.component'
const GameDetailPage = (props) => {
const {games, match} = props
const urlparam =match.params.linkUrl
// const games_array = Object.entries(games)
const gameObj=games[urlparam]
console.log('prop',gameObj)
return (
<div className="game-list">
<GameDetails game = {gameObj}/>
</div>
);
};
const mapStateToProps = (state) => ({
games: state.games.games,
});
export default connect(mapStateToProps)(GameDetailPage);
game_details.component.jsx
import React from 'react';
const GameDetails = (props) => {
console.log(props.game.Location)
return(
<div>
Location:{props.game.Location}
<br/>
Price:{props.game.Price}
</div>
)
}
export default GameDetails;
gamelist.component.jsx
import React from "react";
import './game-list.styles.scss'
import GamePreview from "../game-preview/game-preview.component";
import {connect} from 'react-redux'
const GameList=(props)=>{
const {games}=props
console.log(games)
const game_list=Object.entries(games)
console.log(game_list)
return (
<div className="game-list">
{game_list.map(game =>
<GamePreview game = {game[1]}/>)}
</div>
);
}
const mapStateToProps=state=>({
games:state.games.games
})
export default connect(mapStateToProps)(GameList);
gamepreview.component.jsx
import React from "react";
import "./game-preview.styles.scss";
import { withRouter, Route } from "react-router-dom";
import GamePreviewDetail from "../game-preview-detail/game-preview-detail.component";
const GamePreview = (props) => {
const { Location, Time, linkUrl, Price } = props.game;
const { history, match } = props;
return (
<div
className="game-preview"
onClick={() => history.push(`${match.url}/${linkUrl}`)}
>
<div className="game-preview-image">
<p>Picture goes here</p>
</div>
{/* <GamePreviewDetail name = {Location} price={Price}/> */}
<p>Location:{Location}</p>
<p>Price:{Price}</p>
</div>
);
};
export default withRouter(GamePreview);
app.js
import React from 'react';
import './App.css';
//import dependencies
import { Route, Switch } from "react-router-dom";
//import pages
import HomePage from './pages/homepage/homepage'
import GamesPage from './pages/gamespage/gamespage'
import SignInSignUp from './pages/signin-signup-page/signin-signup-page'
import GameDetailPage from "./pages/gamedetailpage/gamedetailpage.component";
import Header from './components/header/header.component';
import { auth, createUserProfileDocument } from './firebase/firebase.utils';
class App extends React.Component{
constructor() {
super();
this.state = {
currentUser: null
}
}
unsubscribeFromAuth = null
componentDidMount() {
this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
if (userAuth) {
const userRef = await createUserProfileDocument(userAuth);
// check if the snapshot has changed (subscribe)
// get the user that we just created or that already exists in the db
userRef.onSnapshot(snapshot => {
this.setState({
currentUser: {
id: snapshot.id,
...snapshot.data()}
})
})
} else {
this.setState({currentUser: userAuth})
}
})
}
componentWillUnmount() {
this.unsubscribeFromAuth();
}
render(){
return(
<div>
<Header currentUser = {this.state.currentUser}/>
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/games" component={GamesPage} />
<Route exact path="/signin" component={SignInSignUp} />
</Switch>
</div>
)
}
}
export default App;
I would try using useParams hook instead. Then capturing any changes of linkUrl with useEffect hook. Also introducing gameObj with useState.
useParams returns an object of key/value pairs of URL parameters. Use it to access match.params of the current <Route>.
If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
Try to modify <GameDetailPage /> component as the following:
import React, { useState, useEffect } from 'react';
import { useParams } from "react-router-dom";
// other imports
const GameDetailPage = (props) => {
const { games } = props;
let { linkUrl } = useParams();
const [ gameObj, setGameObj ] = useState(null);
useEffect(() => {
if (games) {
const newGameObj = games[linkUrl];
console.log('game object', newGameObj);
setGameObj(newGameObj);
}
}, [games, linkUrl]);
return <div className="game-list">
{ gameObj && <GameDetails game={ gameObj } /> }
</div>
}
+1 - null check:
Also you can see a null check in the return statement for gameObj which helps rendering only that case once you have a value in games array with found linkUrl value.
I hope this helps!

Classless react states?

Im trying to build a simple app with react-boilerplate, the containers(basically views) and components do not use classes to create new components, instead they are basic functions. Typically you add a constructor or direct state to a class, since there are no classes i dont know where to add the state definition. Nowhere ive added a constructer or state definition works, where can you add simple react (NO redux) state list or constructor within this pattern for this view?
example of a container
/*
* HomePage
*
* This is the first thing users see of our App, at the '/' route
*/
import React, { useEffect, memo } from 'react';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import { FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { createStructuredSelector } from 'reselect';
import { useInjectReducer } from 'utils/injectReducer';
import { useInjectSaga } from 'utils/injectSaga';
import {
makeSelectRepos,
makeSelectLoading,
makeSelectError,
} from 'containers/App/selectors';
import H2 from 'components/H2';
import ReposList from 'components/ReposList';
import AtPrefix from './AtPrefix';
import CenteredSection from './CenteredSection';
import Form from './Form';
import Input from './Input';
import Section from './Section';
import messages from './messages';
import { loadRepos } from '../App/actions';
import { changeUsername, setHomeVisible } from './actions';
import { makeSelectUsername, makeHomeVisible } from './selectors';
import reducer from './reducer';
import saga from './saga';
import NavBar from './NavBar';
import ButtonLink from './ButtonLink';
const key = 'home';
export function HomePage({
username,
loading,
error,
repos,
onSubmitForm,
onChangeUsername,
homeVisible,
makeHomeVisible,
setHomeVisible
}) {
useInjectReducer({ key, reducer });
useInjectSaga({ key, saga });
useEffect(() => {
// When initial state username is not null, submit the form to load repos
if (username && username.trim().length > 0) onSubmitForm();
}, []);
const reposListProps = {
loading,
error,
repos,
};
return (
<article>
<Helmet>
<title>title</title>
<meta
name="description"
content=""
/>
</Helmet>
<NavBar>
<ButtonLink to="/" onClick={makeHomeVisible}>
<FormattedMessage {...messages.websites} />
</ButtonLink>
<ButtonLink to="/apps" >
<FormattedMessage {...messages.apps} />
</ButtonLink>
</NavBar>
<div className={`home ${this.state.visible === false ? 'hidden': ''}`}>
<Section>
<H2>
<FormattedMessage {...messages.trymeHeader} />
</H2>
<Form onSubmit={onSubmitForm}>
<label htmlFor="username">
<FormattedMessage {...messages.trymeMessage} />
<AtPrefix>
<FormattedMessage {...messages.trymeAtPrefix} />
</AtPrefix>
<Input
id="username"
type="text"
placeholder="mxstbr"
value={username}
onChange={onChangeUsername}
/>
</label>
</Form>
<ReposList {...reposListProps} />
</Section>
</div>
</article>
);
}
HomePage.propTypes = {
loading: PropTypes.bool,
homeVisible: PropTypes.bool,
error: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
repos: PropTypes.oneOfType([PropTypes.array, PropTypes.bool]),
onSubmitForm: PropTypes.func,
username: PropTypes.string,
onChangeUsername: PropTypes.func,
makeHomeVisible: PropTypes.func,
};
const mapStateToProps = createStructuredSelector({
repos: makeSelectRepos(),
username: makeSelectUsername(),
loading: makeSelectLoading(),
error: makeSelectError(),
homeVisible: makeHomeVisible(),
});
export function mapDispatchToProps(dispatch) {
return {
onChangeUsername: evt => dispatch(changeUsername(evt.target.value)),
makeHomeVisible: evt => dispatch(setHomeVisible(evt.target.value)),
onSubmitForm: evt => {
if (evt !== undefined && evt.preventDefault) evt.preventDefault();
dispatch(loadRepos());
},
};
}
const withConnect = connect(
mapStateToProps,
mapDispatchToProps,
);
export default compose(
withConnect,
memo,
)(HomePage);
As per the React Docs, you can use the useState hook to save data to state. There is no "state list or constructor" but you can simply access the props you pass in and decide to save those into state if they are going to be manipulated - if not stick to using the props.
Codesandbox Demo
Basic Example:
function Child(props) {
let [name, setName] = useState(props.data.name);
function updateName () {
setName('The Dude');
}
return (
<div className="App">
<h2>{name}</h2>
<button onClick={updateName}>Update</button>
</div>
);
};
function App() {
let [data, setData] = useState({name: 'dude'});
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Child data={data}/>
</div>
);
}

Uncaught (in promise) TypeError: Cannot read property 'map' of undefined

So, when I am trying to access my news props to display news title to my page I am receiving and error like this one:
Error Msg
import React, { Component } from 'react';
import Search from './Search';
import { connect } from 'react-redux';
import NewsItem from './NewsItem';
class NewsResults extends Component {
render() {
return (
<div>
<Search />
{this.props.news.map(item => {
return <NewsItem new={item} key={item.objectID} showButton={true}/>
})
}
</div>
)
}
}
function mapStateToProps(state) {
console.log(state)
return {
news: state.news
}
}
export default connect(mapStateToProps, null)(NewsResults);
NewsItem.js is just a component through which I will display the results on my application.
import React, { Component } from 'react';
class NewsItem extends Component {
render(){
return(
<div className="col-sm-12 col-sm-3">
<div className="thumbnail">
<div className="caption">
<h3>{this.props.new.title}</h3>
</div>
</div>
</div>
)
}
}
export default NewsItem;
This is where I'm fetching my information from an api and then I want to display on my page using maps
class Search extends Component {
constructor(props) {
super(props);
this.state = {
query: ''
};
}
search(){
console.log('Search button clicked', this.state.query);
let url = `http://hn.algolia.com/api/v1/search_by_date?query=${this.state.query}`;
// console.log(url);
fetch(url, {
method: 'GET'
}).then(response=> response.json())
.then(jsonObject => {this.props.news(jsonObject.results)});
}
This is my redux action code in action.js file
export const NEWS = "NEWS";
export function news(items) {
const action = {
type: NEWS,
items
}
return action;
}
This is the reducer file
import { NEWS } from '../actions';
const initialState = {
news: []
}
export default function (state= initialState, action) {
switch(action.type) {
case NEWS:
console.log("News are ",action.items);
return {
...state,
news: action.items
};
default:
return state;
}
};
So now I have changed my reducer to be in 2 seperate files I will post below. Also by doing that error message changed to this:
This is the new Error I am getting now
My reducer files are below:
import { NEWS } from '../actions';
export default function news(state = [], action) {
switch(action.type) {
case NEWS:
console.log("News are ",action.items);
return action.items;
default:
return state;
}
}
Second Reducer File:
import news from './news_reducer';
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
news
});
export default rootReducer;
Then I am importing my rootReducer from reducer folder in index.js outside of source folder where my redux store is.
This is how I am creating my store in index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import registerServiceWorker from './registerServiceWorker';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root'));
registerServiceWorker();
Now, My problem is that I am trying to send data from actions but reducer isn't recieving it for some reason.
Another Error popped up now. Another Error

React-Auth0? Working! React-Redux-Auth0? I am losing my mind :/

This is a really long post, but I really need some help :/
I will be eternally grateful if someone would be able to help.
I have managed to get Auth0 working for an application i am working on with just react. It is an Overwatch SR tracker, and is essentially just a spreadsheet so I wasn't too concerned with protecting backend routes when I make them. There isn't any private information there.
My application state/props network became too complicated to manage, and through the process of implementing redux I simply cannot get it to work. I've been at it for three days, and I'm running out of ideas. Do I need Thunk with my current Auth setup to do this? I would imagine it is async since it needs to go get something that isnt there.
Granted I am a junior Dev, and dont have much experience with authentication. Can someone take a look at my working react application and guide me in the direction of what i may need to do to set it up with redux? I do have an understanding of redux flow, so if the proper method to do this was explained to me i feel i might get it.
here is some code:
my Auth.js file :
/*eslint no-restricted-globals: 0 */
import auth0 from "auth0-js";
import jwtDecode from 'jwt-decode';
const LOGIN_SUCCESS_PAGE = '/menu';
const LOGIN_FAILURE_PAGE = '/';
export default class Auth {
auth0 = new auth0.WebAuth({
domain: "redacted.auth0.com",
clientID: "redacted",
redirectUri: "http://localhost:3000/callback",
audience: "https://redacted.auth0.com/userinfo",
responseType: "token id_token",
scope: "openid profile"
});
constructor() {
this.login = this.login.bind(this);
}
login() {
this.auth0.authorize();
}
handleAuthentication() {
this.auth0.parseHash((err, authResults) => {
if (authResults && authResuslts.accessToken && authResults.idToken) {
let expiresAt = JSON.stringify((authResults.expiresIn) * 1000 + new Date().getTime());
localStorage.setItem("access_token", authResults.accessToken);
localStorage.setItem("id_token", authResults.idToken);
localStorage.setItem("expires_at", expiresAt);
location.hash = "";
location.pathname = LOGIN_SUCCESS_PAGE;
} else if (err) {
location.pathname = LOGIN_FAILURE_PAGE;
console.log(err);
}
});
}
isAuthenticated() {
let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
return new Date().getTime() < expiresAt;
}
logout() {
localStorage.removeItem("access_token");
localStorage.removeItem("id_token");
localStorage.removeItem('expires_at');
location.pathname = LOGIN_FAILURE_PAGE;
}
getProfile() {
if (localStorage.getItem("id_token")) {
console.log(jwtDecode(localStorage.getItem("id_token")))
console.log(localStorage.getItem("id_token"));
return jwtDecode(localStorage.getItem("id_token"));
} else {
return {
name: 'Anon',
nickname: 'Anon',
picture: 'placeholder',
uid: null,
}
}
}
}
my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import Auth from './Auth';
import { BrowserRouter } from 'react-router-dom';
const auth = new Auth();
let state = {};
window.setState = (changes) => {
state = Object.assign({}, state, changes)
ReactDOM.render(
<BrowserRouter>
<App {...state} />
</BrowserRouter>,
document.getElementById('root'));
}
/* eslint no-restricted-globals: 0*/
let getUserProfile = auth.getProfile();
let initialState = {
owSrTrackInfo: {
infoSaved: false,
accounts: [],
},
user: getUserProfile,
location: location.pathname.replace(/^\/?|\/$/g, ""),
auth,
}
window.setState(initialState);
registerServiceWorker();
my App.js file:
import React, { Component } from "react";
import "./App.css";
import Main from "./Components/Main/Main";
import Menu from "./Pages/Menu/Menu";
import NotFound from "./Components/NotFound/NotFound";
import Callback from './Components/Callback/Callback';
import Header from './Components/Header/Header';
class App extends Component {
render() {
let mainComponent = "";
switch (this.props.location) {
case "":
mainComponent = <Main {...this.props} />;
break;
case "callback":
mainComponent = <Callback />
break;
case "menu":
mainComponent = this.props.auth.isAuthenticated() ? < Menu {...this.props} /> : <NotFound />;
break;
default:
mainComponent = <NotFound />;
}
return (
<div className="app">
<Header {...this.props} />
{mainComponent}
</div>
);
}
}
export default App;
my Callback.js component:
import React, {Component} from 'react';
import Auth from '../../Auth'
export default class Callback extends Component {
componentDidMount() {
const auth = new Auth();
auth.handleAuthentication();
}
render() {
return(
<p className="loading">Loading.....</p>
)
}
}
My current MAIN.js component:
import React, { Component } from "react";
export default class Main extends Component {
render() {
console.log(this.props.auth.getProfile())
return (
<div className="container">
<div className='container--logged-out'>
<h1 className="heading u-margin-bottom-small">welcome to redacteds' overwatch sr tracker</h1>
<p>Hello there {this.props.user.nickname}! Sign in single click or email via Auth0 so we can save your results, and make the app usable by more than one person. I intend for more than one person to use this, so just to launch it and so the app knows your spreadsheet from someone elses I'll tie each user to their own UID. Feel free to come back, log in, and get your spreadsheet for the season back anytime.</p>
</div>
Go to the app menu!
<button onClick={() =>this.props.auth.getProfile()}>asdgkljsdngk</button>
</div>
);
}
}
my current HEADER.js component:
import React, { Component } from 'react';
export default class Header extends Component {
render() {
return (
<header className="header">
<h1 className='header__text'>SR TRACKER</h1>
{this.props.auth.isAuthenticated() ?
<button className='btn btn--logout' onClick={() => this.props.auth.logout()}>Logout</button>
:
<button className='btn btn--login' onClick={() => this.props.auth.login()}>Login or Sign Up</button>}
</header>
)
}
}
I simply want to map this authentication to a redux store instead to be consitent with the rest of my app (when redux is implemented) I have blown it away and started over multiple times, but a rough idea of what my redux flow might look like is like this template i use and have successfully implemented several times:
redux store:
import { createStore, compose, applyMiddleware } from 'redux';
import { createLogger } from 'redux-logger';
import thunk from 'redux-thunk';
import rootReducer from './reducers/rootReducer';
export default function configureStore(initialState) {
const middleware = [
createLogger({
collapsed: false,
duration: true,
diff: true,
}),
thunk,
];
const store = createStore(
rootReducer,
initialState,
compose(
applyMiddleware(...middleware),
window.devToolsExtension ? window.devToolsExtension() : format => format, // add support for Redux dev tools),
),
);
return store;
}
actionTypes.js in actions folder:
const actions = {
GET_FRIENDS: 'GET_FRIENDS',
REMOVE_FRIEND: 'REMOVE_FRIEND',
GET_MOVIES: 'GET_MOVIES',
GET_MOVIES_SUCCESS: 'GET_MOVIES_SUCCESS',
GET_MOVIES_FAILURE: 'GET_MOVIES_FAILURE',
DEVIN_FUN: 'DEVIN_FUN',
};
export default actions;
Sample actions page:
import axios from 'axios';
import actionTypes from './actionTypes';
export const getMoviesSuccess = data => {
return {
type: actionTypes.GET_MOVIES_SUCCESS,
data,
};
};
export const getMoviesFailure = () => {
return {
type: actionTypes.GET_MOVIES_FAILURE,
};
};
export const devinIsHavingFun = () => {
return {
type: actionTypes.DEVIN_FUN,
};
};
export const retrieveMovies = () => {
return function(dispatch) {
const API_KEY = 'trilogy';
dispatch(devinIsHavingFun());
axios
.get(`http://www.omdbapi.com?apikey=${API_KEY}&s=frozen`)
.then(data => {
dispatch(getMoviesSuccess(data.data.Search));
})
.catch(error => {
console.log(error);
dispatch(getMoviesFailure());
});
};
};
in the reducers folder wed have some files like initialState.js and root reducer that look like this respectively:
initialState.js:
export default {
friends: [],
movies: [],
};
rootReducer.js:
import { combineReducers } from 'redux';
import friends from './friendReducer';
import movies from './movieReducer';
const rootReducer = combineReducers({
friends,
movies,
});
export default rootReducer;
and a sample reducer:
import actionTypes from '../actions/actionTypes';
import initialState from './initialState';
export default function movieReducer(state = initialState.movies, action) {
switch (action.type) {
case actionTypes.GET_MOVIES_SUCCESS: {
return action.data;
}
default: {
return state;
}
}
}
I just dont know what to do. Do i need to use thunk? am I overthinking this? I'm pulling my hair out.
I also do connect my components in this fashion when redux is implemented :
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as friendActionCreators from './actions/friendActions';
import * as movieActionCreators from './actions/movieActions';
....................
function mapStateToProps(state) {
return {
myFriends: state.friends,
movies: state.movies,
};
}
function mapDispatchToProps(dispatch) {
return {
friendActions: bindActionCreators(friendActionCreators, dispatch),
movieActions: bindActionCreators(movieActionCreators, dispatch),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Please let me know if anyone can point me in the right direction. thank you so much in advance.

Why doesn't action fire in my react\redux app?

Currently, I'm working on a small application that utilizes modals. I don't want to use 'ready-to-use' packages like react-modal and instead decided to try to do it on my own.
1) A reducer in src/reducers/modalReducer.js
const modalReducer = (state = {
show: true,
}, action) => {
switch (action.type) {
case 'TOGGLE_MODAL':
console.log('reducer worked out')
state = {...state, show: !state.show }
break
default:
return state
}
}
export default modalReducer
My reducers/index.js
import { combineReducers } from 'redux'
import modalReducer from './modalReducer'
const reducers = combineReducers({
modal: modalReducer
})
export default reducers
2) A store in src/store.js
import { createStore } from 'redux'
import reducer from './reducers/index'
export default createStore(reducer)
3) A Modal component in src/components/Modal.js. I want this component to be reusable and contain input forms which I'll add later.
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { toggleModal } from '../actions/index'
import { bindActionCreators } from 'redux'
import '../css/Modal.css'
class Modal extends Component {
render () {
if(!this.props.show) {
return (<h1>FUC YOU</h1>)
}
console.log('HELLLO' + this.props.show)
return (
<div className='backdrop'>
<div className='my-modal'>
<div className='footer'>
<button className='close-btn' onClick={ () => toggleModal }>
X
</button>
</div>
<h1>{ this.props.title }</h1>
<hr/>
<div>
{ this.props.contents }
</div>
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return { show: state.modal.show }
}
const mapDispatchToProps = (dispatch) => {
return {
toggleModal: () => dispatch(toggleModal())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Modal)
My problem is that when I'm pressing the button x, in my modal nothing happens. It means that I did something wrong when was dispatching actions, but I have no idea what I missed...
At this point I just want my empty modal to be closed when the x button is pressed.
In my index.js I have the following structure:
import React from 'react'
import ReactDOM from 'react-dom'
import registerServiceWorker from './registerServiceWorker'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import store from './store.js'
import App from './components/App'
ReactDOM.render(
<Provider store = {store} >
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
, document.getElementById('root'))
registerServiceWorker()
My Modal component is within App
You're not actually calling the toggleModal() action creator. In addition, you're referencing the imported function, not the function you're getting as props:
onClick={ () => toggleModal }
The immediate fix would be: onClick={ () => this.props.toggleModal() }.
Having said that, there's two other ways you can improve this code.
First, you can pass toggleModal directly as the handler for onClick, like:
onClick={this.props.toggleModal}
Second, you can replace the mapDispatch function by using the "object shorthand" syntax supported by connect:
import {toggleModal} from "../actions";
const actions = {toggleModal};
export default connect(mapState, actions)(Modal);
Beyond that, I'd encourage you to read my post Practical Redux, Part 10: Managing Modals and Context Menus, which specifically shows how to implement modal dialogs using React and Redux, and points to additional resources on the topic.

Categories