having a serious challenge with my React/Redux authorization setup and I'm at a loss. Current error is:
HomeHeader.js?8595:26 Uncaught ReferenceError: dispatch is not defined
There's a lot wrong here, and any help would be appreciated.
I'm creating two authorization components, one to register and one to login. The AuthorizationLogin component is what I'm working on first.
I don't know how to get this to pass the event info it grabs form the form fields, put in the variable creds, and then on up through the HomeHeader component, and then again up to the HomePage container. Do I put all of the authorization components into one enormous HomeHeader component?
Here's the main code and flow. Code isn't loading right into StackOverflow for some reason.
HomePage.js
import React from 'react';
import {connect} from 'react-redux';
import * as actions from '../../../actions/homeEventFormActions';
import HomeHeader from '../homeHeader/HomeHeader';
import HomeEventForm from '../homeEventForm/HomeEventForm';
class HomePage extends React.Component {
constructor(props) {
super(props);
}
render() {
const { dispatch } = this.props;
return (
<div>
< HomeHeader />
< HomeEventForm
onSubmit={this.props.onSubmit}
/>
</div>
);
}
}
function mapStateToProps(state) {
return {
homeEventForm: state.homeEventForm
};
}
function mapDispatchToProps(dispatch) {
return {
onSubmit: (eventName) => dispatch(actions.createEventButton(eventName)),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(HomePage);
HomeHeader.js
import React, { Component, PropTypes } from 'react';
import AuthorizeLogin from '../../Authorization/AuthorizeLogin';
import AuthorizeRegister from '../../Authorization/AuthorizeRegister';
import { loginUser } from '../../../actions/authorizationActions';
class HomeHeader extends React.Component {
constructor() {
super();
}
_handleChange(eventKey) {
...
<AuthorizeLogin
onLoginClick={ (creds) => dispatch(loginUser(creds))}
/>
...
}
return;
}
render() {
const { dispatch } = this.props;
return (
...
<Modal.Header closeButton onClick={ ()=> this._handleChange(5)}>
...
);
}
}
export default HomeHeader;
AuthorizeLogin.js
import React from 'react';
class AuthorizeLogin extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {};
this._login = this._login.bind(this);
}
_login(e) {
e.preventDefault;
const email = this.refs.email;
const password = this.refs.password;
const creds = { email: email.value.trim(), password: password.value.trim() };
this.props.onLoginClick(creds);
}
render() {
return (
<Form horizontal onSubmit={this._login}>
<h4 className="authEmailText">Login with your email</h4>
<input type="email" placeholder="urawesome#example.com" ref='email' />
<input type="password" placeholder="Password" ref='password' />
</Form>
);
}
}
export default AuthorizeLogin;
All the actions should be dispatched from container. In this case, the container should have the dispatch.
function mapDispatchToProps(dispatch) {
return {
onSubmit: (eventName) => dispatch(actions.createEventButton(eventName)),
onLogin: (creds) => dispatch(loginUser(creds)),
};
}
The onLogin should be passed to downstream components via props:
<HomeHeader onLogin={this.props.onLogin} />
<AuthorizeLogin
onLoginClick={this.props.onLogin}
/>
Related
When i enter my React Router-dom i point my routes to a validation page.
In event aim loged in or not, i push my route(history) to required page but i keep getting bellow error.
Error: Objects are not valid as a React child (found: object with keys {$$typeof, type, compare, WrappedComponent, displayName}). If you meant to render a collection of children, use an array instead.
in Unknown (at RequiredAuth.js:34)
in RequireAuth (created by ConnectFunction)
in ConnectFunction (created by Context.Consumer)
in Route (at App.js:23)
in Switch (at App.js:18)
in Router (at App.js:17)
in div (at App.js:16)
in App (created by ConnectFunction)
in ConnectFunction (at Dashbord.js:14)
in div (at Dashbord.js:14)
in DashBoard (created by ConnectFunction)
in ConnectFunction (at src/index.js:10)
in Provider (at src/index.js:9)
App.js
import React from 'react';
import { Router, Route, Redirect, Switch } from 'react-router-dom';
import { history } from './configureStore';
import { allRoutes } from './routes';
import NotFound from './pages/404';
import RequiredAuth from './components/RequiredAuth';
import NotRequiredAuth from './components/NotRequiredAuth';
import DashBoard from './pages/Dashbord';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
class App extends React.Component {
render() {
return (
<div style={{ height: '100%' }}>
<Router history={history}>
<Switch>
{allRoutes
.filter(route => route.visible)
.map((route, index) => {
return (
<Route
exact={route.exact}
path={route.path}
key={index}
component={RequiredAuth(route.component)}
/>
)
})}
<Route path={'/:404_path'} key={'404'} component={NotFound} />
<Redirect to="/dashboard" />
</Switch>
</Router>
</div>
);
}
}
App.displayName = 'App';
const mapDispatchToProps = dispatch => {
return bindActionCreators({ }, dispatch);
};
const mapStateToProps = state => {
return {
};
};
export default DashBoard(
connect(
mapStateToProps,
mapDispatchToProps
)(App)
);
RequiredAuth.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import { history } from '../configureStore';
export default function (ComposedComponent) {
class Authentication extends Component {
constructor(props){
super(props);
this.props = props;
}
componentDidMount() {
const { auth } = this.props
if (!auth.success) {
history.push('/login');
}
}
componentDidUpdate() {
const { auth } = this.props
if (!auth.success) {
history.push('/login');
}
}
PropTypes = {
router: PropTypes.object
}
render() {
return <ComposedComponent {...this.props} />;
}
}
Authentication.propTypes = {
location: PropTypes.object
}
Authentication.displayName = 'RequireAuth'
function mapStateToProps(state) {
return { auth: state.auth };
}
const mapDispatchToProps = dispatch => bindActionCreators({ }, dispatch);
return connect(mapStateToProps, mapDispatchToProps)(Authentication);
}
Dashbord.js
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { ShouldRender } from '../components/basic/ShouldRender';
export default function(ComposedComponent) {
class DashBoard extends Component {
render() {
const {auth} = this.props
if (!auth.success) return <div>{ComposedComponent && <ComposedComponent />}</div>;
return (
<div>
<ShouldRender if={!auth.success}>
{ComposedComponent && <ComposedComponent />}
</ShouldRender>
<ShouldRender if={auth.success}>
<div style={{ height: '100%' }}>
<div>
<div className='page-container'>
<main className='main-content bgc-grey-100'>
<div id='mainContent'>
<div className='row gap-20 masonry pos-r'>
<div className='masonry-item col-12'>
{ComposedComponent && <ComposedComponent />}
</div>
</div>
</div>
</main>
<footer className='bdT ta-c p-30 lh-0 fsz-sm c-grey-600'>
<span>
Copyright © {new Date().getFullYear()}{' '}
<a
href='https://dataintegrated.co.ke'
target='_blank'
title='Data Integrated'
>
Data Integrated Limited
</a>
. All rights reserved.
</span>
</footer>
</div>
</div>
</div>
</ShouldRender>
</div>
);
}
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({ }, dispatch);
};
function mapStateToProps(state) {
return {
auth: state.auth
};
}
DashBoard.propTypes = {
};
return connect(mapStateToProps, mapDispatchToProps)(DashBoard);
}
Have tried working with HOC react official page but when i implement this validation, i always land my self on this error, but when i remove HOC implementation everything renders perfectly.
try using a return statement in your HOC or change your function into an arrow function
I.E
export default function(ComposedComponent) {
return class DashBoard extends Component
OR
export default (ComposedComponent) =>{
class DashBoard extends Component
I found several errors in your code, first of all your function definition is wrong, at export default function(ComposedComponent) it must be export default function ComposedComponent () {} Do not put this class class Authentication extends Component {} inside the function, if you want it to be a component create another function for this. Also define which type of components you are going to use: Functional or Class based.
We cannot know how to help you while your code have these several mistakes. Please check them and back again with your updated code.
I have two component in my project one is Tag and the other is LandingTicker so i want when i click Tag componet update state for LandTicker componet, and landticker componet in different file.
how i can do that?
thank you.
Tag component code::
tag/index.js
import React from 'react';
import './index.scss';
class Tag extends React.Component {
handleClick(e) {
let tags = document.querySelectorAll('.show-clickable');
Array.from(tags).map(el => el.classList.remove('selected-tag'))
e.target.classList.add('selected-tag');
/*
Here i should update the state for LandingTicker component.
and remember any component in different file.
How i can do that???
*/
}
render() {
return (
<div
className="show-clickable"
onClick={this.handleClick}
>
click here
</div>
);
}
}
export default Tag;
LandingTicker component code::
LandingTicker/index.js
import React from 'react';
import TickerRow from './TickerRow';
import './index.scss';
class LandingTicker extends React.Component {
state = {
coin: 'USD'
}
render() {
return (
<div className="landing-ticker__body">
{selectCoin(this.state.coin)}
</div>
</div>
);
}
}
const selectCoin = (coin) => {
const coins = {
USD: ['BTCUSD', 'ETHUSD', 'EOSUSD', 'LTCUSD'],
EUR: ['BTCEUR', 'ETHEUR', 'EOSEUR'],
GBP: ['BTCGBP', 'EOSGBP'],
JPY: ['BTCJPY', 'ETHJPY'],
};
return (
coins[coin].map(el =>
<TickerRow symbol={el} key={el.toString()} />
)
);
}
export default LandingTicker;
Edit:
my component Hierarchy::
StatusTable
TagsTable
Tag
TickerSearch
LandingTickers
TickersRow
StatusTable component code::
import React from 'react';
import TagsTable from './TagsTable';
import TickerSearch from './TickerSearch';
import LandingTicker from './LandingTicker';
import './StatusTable.scss';
class StatusTable extends React.Component {
render() {
return (
<div className="status-table">
<TagsTable />
<TickerSearch />
<LandingTicker />
</div>
);
}
}
export default StatusTable;
React handle all its component data in the form of state and props(immutable). So it is easy to pass data from parent to child or one component to another using props :
Your Tag.js file:
import React, { Component } from "react";
import LandingTicker from "./LandTicker";
class Tag extends Component {
constructor(props) {
super(props);
this.state = {
trigger: true
};
}
handleClick(e) {
// do all logic here and set state here
this.setState({ trigger: this.state.trigger });
}
render() {
//And then pass this state here as a props
return (
<div className="show-clickable" onClick={this.handleClick}>
click here
<LandingTicker trigger={this.state.trigger} />
</div>
);
}
}
export default Tag;
Inside LandTicker.js file:
import React from 'react';
import TickerRow from './TickerRow';
import './index.scss';
class LandingTicker extends React.Component {
state = {
coin: 'USD'
}
render() {
//Catch your props from parent here
//i.e this.props(it contains all data you sent from parent)
return (
<div className="landing-ticker__body">
{selectCoin(this.state.coin)}
</div>
);
}
}
const selectCoin = (coin) => {
const coins = {
USD: ['BTCUSD', 'ETHUSD', 'EOSUSD', 'LTCUSD'],
EUR: ['BTCEUR', 'ETHEUR', 'EOSEUR'],
GBP: ['BTCGBP', 'EOSGBP'],
JPY: ['BTCJPY', 'ETHJPY'],
};
return (
coins[coin].map(el =>
<TickerRow symbol={el} key={el.toString()} />
)
);
}
export default LandingTicker;
I think this is the best answer for your question if you don't use state management system such as Redux or Mobx.
https://medium.com/#ruthmpardee/passing-data-between-react-components-103ad82ebd17
(you need to check third option)
I learn React Redux and have some issues.
In the code below I do mapStateToProps to listen for changes and I use the mapDispatchToProps to send a notification. When there is a change in the Store I send a Notification. In order for this to work I have to put this Helper in the App.jsx render() method even do this Helper Component code below does not add anything to the App.jsx. I learn React and wonder how I can change this Notefication.js so it listen for mapStateToProps and can do mapDispatchToProps without adding it to App.jsx render().
It just feels so unnecessary to have to add this Component to the App.jsx render only to get the mapStateToProps mapDispatchToProps working?
Notefication.js
import { connect } from "react-redux";
import 'react-redux-notify/dist/ReactReduxNotify.css';
import { createNotification, NOTIFICATION_TYPE_SUCCESS } from 'react-redux-notify';
import { Notify } from 'react-redux-notify';
import React, { Component } from "react";
const mySuccessNotification = {
message: 'You have been logged in!',
type: NOTIFICATION_TYPE_SUCCESS,
duration: 0,
canDismiss: true,
icon: <i className="fa fa-check" />
}
class Helper extends Component {
senNotification() {
const { createNotification } = this.props;
createNotification(mySuccessNotification);
}
render() {
return (
<div>
<Notify />
{this.senNotification()}
</div>
)
}
}
const mapDispatchToProps = dispatch => ({
createNotification: (config) => {
dispatch(createNotification(config))
},
})
const mapStateToProps = state => {
return { badword: state.rootReducer.badword };
};
export default connect(mapStateToProps, mapDispatchToProps)(Helper)
App.jsx
import React, { Component } from "react";
import List from "./List.jsx";
import Form from "./Form.jsx";
import Helper from "../components/Notification";
class App extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
const { addToast } = this.props.actions;
addToast({ text: "Hello, World!" });
}
render() {
return (
<main>
<div className="row mt-5">
<div className="col-md-4 offset-md-1">
<h2>Articles</h2>
<List />
</div>
<div className="col-md-4 offset-md-1">
<h2>Add a new article</h2>
<Form />
</div>
</div>
<Helper/>
</main>
);
}
}
export default App;
React only renders new, if the component values changes. So if the reducer is connected and you load some values which changes, the component renders and the function will be triggered.
I would not trigger the function this.senNotification in the render function I would prefer to use componentDidUpdate to trigger the function.
import { connect } from "react-redux";
import 'react-redux-notify/dist/ReactReduxNotify.css';
import { createNotification, NOTIFICATION_TYPE_SUCCESS } from 'react-redux-notify';
import { Notify } from 'react-redux-notify';
import React, { Component } from "react";
const mySuccessNotification = {
message: 'You have been logged in!',
type: NOTIFICATION_TYPE_SUCCESS,
duration: 0,
canDismiss: true,
icon: <i className="fa fa-check" />
}
class Helper extends Component {
componentDidUpdate (prevProps) {
const { createNotification, badword } = this.props
if(prevProps.badword !== badword) {
this.senNotification()
}
}
senNotification() {
const { createNotification } = this.props;
createNotification(mySuccessNotification);
}
render() {
return <Notify />
}
....
}
I'm having an issue where when I want to dispatch an action, fetchRewardByPromoCodeAction it's saying that the action I want to dispatch is not a function.
In the the form, I use the the event handleer onSubmit then use handleSubmit. I noticed that my props becomes undefined so, which leads me to thinking that the connect function isn't working as expected. Any assistance would be helpful. Here's the code.
import React, { Component } from 'react';
import { connect
} from 'react-redux';
import PromoCodeInput from 'components/promoCodeForm/PromoCodeInput';
import { fetchRewardByPromoCode, resetValidations } from 'rewards/ducks';
import Button from 'button/Button';
export class AdminRewardPage extends Component<Props> {
constructor(props) {
super(props);
this.state = {
promoCodeText: '',
};
}
onPromoCodeChange = (event) => {
this.setState({
promoCodeText: event.target.value,
});
const { resetValidationsAction } = this.props;
resetValidationsAction();
};
handleSubmit = (event) => {
event.preventDefault()
const { fetchRewardByPromoCodeAction } = this.props;
const { promoCodeText } = this.state;
fetchRewardByPromoCodeAction(promoCodeText);
}
render() {
const { promoCodeText } = this.state
return (
<div>
<h1>AdminRewardPage</h1>
<form onSubmit={this.handleSubmit}>
<PromoCodeInput inputValue={promoCodeText} onChangeHandler={this.onPromoCodeChange} />
<Button type="submit" label="Find By PromoCode" fullWidth />
</form>
</div>
)
}
}
const mapDispatchToProps = (dispatch) => ({
resetValidationsAction: () => dispatch(resetValidations()),
fetchRewardByPromoCodeAction: (promoCodeText) => dispatch(fetchRewardByPromoCode(promoCodeText)),
});
export default connect(null, mapDispatchToProps)(AdminRewardPage);
in rewards/ducks.js
export const fetchRewardByPromoCode = (promoCode: string): FSAModel => ({
type: FETCH_REWARD_BY_PROMOCODE,
payload: promoCode,
})
---EDIT--WITH--ANSWER---
#Bartek Fryzowicz below helped lead me to right direction. I forgot to look in my index.js file where my routes are
Previously I had
import { AdminRewardPage } from 'scenes/AdminRewardPage'
instead of
import AdminRewardPage from 'scenes/AdminRewardPage'
<Router history={ history }>
<Switch>
<Route exact path={ `/rewards` } component={AdminRewardPage} />
</Switch>
</Router>
I didn't bother to look how I was importing it.
LESSON
Look at where and HOW your files are being imported and exported.
You're trying to call fetchRewardByPromoCode function inside mapDispatchToProps but such function (fetchRewardByPromoCode) is not declared inside mapDispatchToProps scope nor in parent scope. Maybe you have forgotten to import it?
Answer update:
Please make sure that when you use the component you use default export (not named export) since named export is the presentational component not connected to redux store. You have to use container component connected to redux so make sure you import it like this:
import AdminRewardPage from '/somePath'
not
import { AdminRewardPage } from '/somePath'
I'm having a problem with the function fetch. I'm trying to send just a number for example "1", and I have access to this data in all child components, but after calling fetch, I'm no longer able to access this data.
App.jsx:
import React, { Component } from 'react'
import './App.css';
import fetch from 'isomorphic-fetch'
import Header from './Header'
import Content from './Content'
import Footer from './Footer'
class App extends Component {
constructor(props) {
super(props)
this.state = {
stripdata: null
}
}
componentWillMount() {
fetch(`http://localhost:3000/data/info.json`)
.then(results => results.json())
.then(data => {
this.setState({
stripdata: data
})
// console.log(this.state.stripdata)
})
.catch(err => {
console.log("Didn't connect to API", err)
})
}
render() {
// console.log(this.state.stripdata)
return (
<div className="App">
<Header onQuery={1}/>
{
(this.state.data === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
<Footer />
</div>
);
}
}
export default App;
Content.jsx:
import React, { Component } from 'react'
import Result from './Result'
class Content extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.onResult
};
}
componentWillMount() {
}
render() {
console.log("im an Content: " + this.state.stripdata)
return (
<div className="Content">
<Result stripdata={ this.state.stripdata }/>
</div>
);
}
}
export default Content;
Result.jsx:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
this.state = {
stripdata: this.props.stripdata
};
}
componentWillMount() {
}
render() {
console.log("im the Result: " + this.state.stripdata)
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
Please help. This is blocking my progress.
Fix the issue here:
<Header onQuery={1}/>
{
(this.state.stripdata === null) ? <div className="loading">Loading data...</div> : <Content onResult={this.state.stripdata}/>
}
You need to check properties in state with name stripdata.
And btw, fetch has to be performed in ComponentDidMount, see https://daveceddia.com/where-fetch-data-componentwillmount-vs-componentdidmount/
The problem is that, in your Results, you are only using the value from props once: in the constructor, where you set to state.
You should not set value in state from props. Instead, just use the props directly. Change Result to as following, then it will work proper:
import React, { Component } from 'react'
import PersonCard from './PersonCard'
class Result extends Component {
constructor(props) {
super(props);
// removed setting state from props.stripdata
}
render() {
console.log("im the Result: " + this.props.stripdata) // <-- using props!
return (
<div className="result">
<PersonCard />
</div>
);
}
}
export default Result;
In general it is considered bad practice/antipattern to set state from props.