I am getting this error:
./src/components/Playing.jsx
Line 15: 'aaa' is not defined no-undef
in my Playing.jsx:
import React, { Component } from 'react'
console.log(aaa);
From my Token.jsx
import { connect } from 'react-redux'
imports { Playing } from '../components/Playing'
const mapStateToProps = state => ({
aaa: "asdf"
})
export default connect(mapStateToProps)(Playing)
You won't be able to just console.log() anywhere in the file; it would need to be within some function of the Playing component; and it will also only be available via props, e.g.
class Playing extends React.Component {
componentDidMount() {
console.log(this.props.aaa);
}
render() {
return <span>Playing</span>;
}
}
Related
I am new to using redux for React Native and am testing it with a simple case. I have been able to successfully connect to the store, and I can see the action is dispatched properly using the redux debugger, however, the store is not updating in the debugger. I've tried several different implementations, but nothing is working. Any help would be appreciated!
Component:
import React, { PureComponent } from 'react'
import { Text, TouchableOpacity, SafeAreaView, Alert, Button } from 'react-native'
import { Navigation } from 'react-native-navigation';
import { connect } from 'react-redux'
import simpleAction from '../store/actions/simpleAction'
class App2 extends PureComponent {
constructor(props){
super(props);
}
pressRedux = () => {
const data = 'hello'
this.props.simpleAction(data)
}
render() {
return (
<SafeAreaView>
<Text>
{this.props.state.simpleReducer.text}
</Text>
<Button onPress = {this.pressRedux} title = 'Redux' />
</SafeAreaView>
)
}
}
function mapStateToProps(state) {
return {
state: state
};
}
const mapDispatchToProps = {
simpleAction
}
export default connect(mapStateToProps, mapDispatchToProps)(App2);
Action:
import {SET_TEXT} from '../types/types'
export default function simpleAction(data) {
return({
type: SET_TEXT,
payload: data
})
}
reducer:
import SET_TEXT from '../types/types'
const INITIAL_STATE = {
text: 'Hi'
}
const simpleReducer = (state = INITIAL_STATE, action ) => {
switch(action.type){
case SET_TEXT:
return { ...state, text: action.payload};
default:
return state;
}
}
export default simpleReducer;
The code you've shared here looks correct. Only thing I can suggest is, if you're seeing the action come through in the debugger, your issue is either with the data/payload or logic within simpleReducer.
In this case you have it properly stripped down so I'd almost think this isn't actually the code you are running, it might be something in your build process?
I want to start my React microapp with props I'm passing from Single SPA (customProps). The only way I've figured out is:
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import App from './where/my/root/is.js';
function domElementGetter() {
return document.getElementById("mounting-node")
}
let EnhancedRootComponent = App; /* 1 */
const reactLifecycles = singleSpaReact({
React,
ReactDOM,
rootComponent: EnhancedRootComponent, /* 1 */
domElementGetter,
})
export const bootstrap = [
(args) => {
/* 2 */ EnhancedRootComponent = () => <App myArgs={args.thePropsIWannaPass} />;
return Promise.resolve();
},
reactLifecycles.bootstrap,
];
export const mount = [reactLifecycles.mount];
export const unmount = [reactLifecycles.unmount];
This does work (I can see and use the passed props in my component) but I'm not completely OK with the fact that the root component changes in between calling singleSpaReact (1) and calling bootstrap(2). Would there be side effects to this that I'm not seeing now? Does anyone know a better approach for this?
You have this value inside the props variable without this reassign.
Check this out:
Root-config.js, file responsible for passing prop to microfrontend
import { registerApplication, start } from 'single-spa';
import * as isActive from './activity-functions';
registerApplication('#company/micro2', () => System.import('#company/micro2'), isActive.micro2);
registerApplication('#company/micro1', () => System.import('#company/micro1'), isActive.micro1, { "authToken": "test" });
start();
micro1 Root.tsx
import React from 'react';
export default class Root extends React.Component {
constructor(props: any){
super(props)
}
state = {
hasError: false,
};
componentDidCatch() {
this.setState({ hasError: true });
}
render() {
console.log(this.props)
return (
<div>test</div>
);
}
}
console.log output:
props:
authToken: "test" <---- props which you pass
name: "#company/micro1"
mountParcel: ƒ ()
singleSpa: {…}
__proto__: Object
for more advance usage
const lifecycles = singleSpaReact({
React,
ReactDOM,
loadRootComponent: (props) =>
new Promise((resolve, reject) => resolve(() =>
<Root {...props} test2={'test2'}/>)),
domElementGetter,
});
I am working on a simple react-redux project that gets information about movies from the OMDB api based on search term provided by the user. I am currently having trouble trying to get text typed into the searchbar to update the store value corresponding to the title of the film to search for. I'm fairly new to react and completely new to redux I've only finished one other redux project before and I set up my actions and reducers in the exact same way as last time but this time I'm running into "Uncaught TypeError: dispatch is not a function". This was not a problem I encountered in the previous project and my google searching has not been very helpful thus far.
I've searched this problem on google and only found a few results and none of them seem to be having the exact same issue as me, they involve using mapDispatchToProps which I'm not using inside of my connect function. Supposedly when you write a mapStateToProps like I have, dispatch should just be passed down as a prop to the connected component but whenever I try to access it I get the aforementioned "Uncaught TypeError: dispatch is not a function" error.
here is the index.js for my component
import { connect } from 'react-redux';
import MovieSearch from './MovieSearchContainer';
import {
updateSearchTerm,
getMovies
} from './movieSearchActions';
function mapStateToProps(state){
return {
title: state.movieSearch.title,
year: state.movieSearch.year,
plot: state.movieSearch.plot,
released: state.movieSearch.released,
runtime: state.movieSearch.runtime,
genre: state.movieSearch.genre,
plot: state.movieSearch.plot,
ratings: {
IMDB: state.movieSearch.ratings.IMDB,
Metascore: state.movieSearch.ratings.Metascore
},
posterUrl: state.movieSearch.posterUrl,
cachedMovies: state.movieSearch.cachedMovies
};
}
export default connect(mapStateToProps)(MovieSearch);
here is my action
export function updateSearchTerm(searchTerm){
return {
type: "UPDATE_SEARCH_TERM",
payload: { searchTerm }
}
}
here is my jsx component
import React from 'react';
import PropTypes from 'prop-types';
import {
updateSearchTerm,
getMovies
} from './movieSearchActions';
export default class MovieSearchContainer extends React.Component
{
constructor(props) {
super(props);
this.handleUpdateSearchTerm =
this.handleUpdateSearchTerm.bind(this);
}
handleUpdateSearchTerm(event){
const { dispatch } = this.props;
const { value } = event.target;
dispatch(updateSearchTerm(value));
}
render() {
return (
<div>
<h1 className='text-center'>Movie Finder</h1>
<input type='text' className='col-sm-11' id='searchBar'
onChange={ this.handleUpdateSearchTerm }/>
<button type='button' id='getMovies' className='col-sm-
1'>Go!</button>
</div>
)
}
}
MovieSearchContainer.propTypes = {
store: PropTypes.object
}
here is the reducer
export default function movieSearchReducer(state = defaultState,
action) {
const { type, payload } = action;
switch(type){
case 'UPDATE_SEARCH_TERM': {
return {
...state,
title: payload.title
}
}
default: {
return state;
}
}
}
I expect changes in the searchbar on the component on the page to be reflected in the redux store, but instead I just get this error
The dispatch prop is only available when you are directly interacting with the redux-store. When you define something like mapDispatchToProps() and pass it as the 2nd argument to connect(), dispatch, gets passed to mapDispatchToProps().
const mapDispatchToProps = (dispatch) => {
return{
actionCreator: (arg) => {
dispatch(actionCreator(arg))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Component)
If you dont want to define mapDispatchToProps(), you can effectively bind your action-creators by passing in an object to connect() as the 2nd argument. This implicitly binds dispatch to the action-creators:
import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { updateSearchTerm, getMovies } from "./movieSearchActions";
class MovieSearchContainer extends React.Component {
constructor(props) {
super(props);
this.handleUpdateSearchTerm = this.handleUpdateSearchTerm.bind(this);
}
handleUpdateSearchTerm(event) {
const { value } = event.target;
this.props.updateSearchTerm(value);
}
render() {
console.log(this.props.movies);
return (
<div>
<h1 className="text-center">Movie Finder</h1>
<input
type="text"
className="col-sm-11"
id="searchBar"
onChange={this.handleUpdateSearchTerm}
/>
<button
type="button"
id="getMovies"
className="col-sm-
1"
>
Go!
</button>
</div>
);
}
}
MovieSearchContainer.propTypes = {
store: PropTypes.object
};
const mapStateToProps = state => {
return {
title: state.movieSearch.title,
year: state.movieSearch.year,
plot: state.movieSearch.plot,
released: state.movieSearch.released,
runtime: state.movieSearch.runtime,
genre: state.movieSearch.genre,
plot: state.movieSearch.plot,
ratings: {
IMDB: state.movieSearch.ratings.IMDB,
Metascore: state.movieSearch.ratings.Metascore
},
posterUrl: state.movieSearch.posterUrl,
cachedMovies: state.movieSearch.cachedMovies
};
};
export default connect(
mapStateToProps,
{
updateSearchTerm,
getMovies
}
)(MovieSearchContainer);
With that, you do not need to explicitly call dispatch to use your action-creator. Simply use this.props.nameOfActionCreator()
See sandbox for example: https://codesandbox.io/s/simple-redux-7s1c0
I think you should connect your component inside your jsx file. Then you can access with this.props.yourFunctionToDispatch
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import {
updateSearchTerm,
getMovies
} from './movieSearchActions';
class MovieSearchContainer extends React.Component
{
constructor(props) {
super(props);
this.handleUpdateSearchTerm =
this.handleUpdateSearchTerm.bind(this);
}
handleUpdateSearchTerm(event){
const { dispatch } = this.props;
const { value } = event.target;
dispatch(updateSearchTerm(value));
}
render() {
return (
<div>
<h1 className='text-center'>Movie Finder</h1>
<input type='text' className='col-sm-11' id='searchBar'
onChange={ this.handleUpdateSearchTerm }/>
<button type='button' id='getMovies' className='col-sm-
1'>Go!</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
title: state.movieSearch.title,
year: state.movieSearch.year,
plot: state.movieSearch.plot,
released: state.movieSearch.released,
runtime: state.movieSearch.runtime,
genre: state.movieSearch.genre,
plot: state.movieSearch.plot,
ratings: {
IMDB: state.movieSearch.ratings.IMDB,
Metascore: state.movieSearch.ratings.Metascore
},
posterUrl: state.movieSearch.posterUrl,
cachedMovies: state.movieSearch.cachedMovies
};
}
MovieSearchContainer.propTypes = {
store: PropTypes.object
}
export default connect(mapStateToProps, {yourFunctionToDispatch})(MovieSearchContainer);
I have this module in ./src/utils/errorPopup.js
import { Toast } from 'native-base';
export default function errorPopup(problem = 'process your request') {
Toast.show({
text: `Unfortunately we cannot ${problem}. An error report has been created and we will look into it shortly. Please get in touch with us if the problem doesn't disappear in the next 6 business hours.`,
position: 'bottom',
buttonText: 'Okay'
});
}
I then try and call it inside the componentWillMount method of ./src/components/JobList.js and it says Uncaught ReferenceError: errorPopup is not defined.
import React, { Component } from 'react';
import { View } from 'react-native';
import axios from 'axios';
import errorPopup from '../utils/errorPopup';
export default class JobsList extends Component {
constructor() {
super();
this.state = {
someObject: undefined
};
}
componentWillMount() {
axios.get('http://api.test.dev:5000/')
.then(response => {
this.setState({ someObject: response.data })
})
.catch(() => {
errorPopup('fetch your accepted and available jobs');
});
}
render() {
return (
<View />
);
}
}
Strangely enough, when I debug and use the console, I can see an object _errorPopup2.
How can I call errorPopup() without changing the design pattern of utils that I adopted from here?
I'm new to redux and having trouble wrapping my head around presentational and container components.
Relevant stack:
react v0.14.8
react-native v0.24.1
redux v3.5.2
react-redux v4.4.5
The issue:
I have a login button component, which when rendered checks the login status and calls the onSuccessfulLogin action which updates the state with the user's Facebook credentials.
However, when trying to separate this into separate presentational/container components, I'm unable to call the onSuccessfulLogin action: Error: onSuccessfulLogin is not defined.
What am I doing wrong here? I'd imagine there's something simple that I'm not understanding with the relationship between the two components and the connect() function.
Presentational Component (Login.js)
import React, { PropTypes } from "react-native";
import FBLogin from "react-native-facebook-login";
import UserActions from "../users/UserActions";
class LoginPage extends React.Component {
render() {
const { userData, onSuccessfulLogin } = this.props;
return (
<FBLogin
permissions={["email","user_friends"]}
onLoginFound= { data => {
onSuccessfulLogin(data.credentials);
}}
/>
)
}
};
export default LoginPage;
Container Component (LoginContainer.js)
import { connect } from 'react-redux';
import LoginPage from "../login/LoginPage";
import UserActions from "../users/UserActions";
const mapDispatchToProps = (dispatch) => {
return {
onSuccessfulLogin: (userData) => {
dispatch(UserActions.userLoggedIn(userData))
}
}
}
const mapStateToProps = (state) => {
return {
userData: state.userData
}
}
const LoginContainer = connect(
mapStateToProps,
mapDispatchToProps
)(LoginPage);
export default LoginContainer;
Also, if I wanted to make the updated state.userData accessible to the LoginPage component, how would I do that? Any help is appreciated!
Solved! When using ES6 classes, you're required to call super(props) in a constructor method in order to access the container's properties in the connected presentational component:
class LoginPage extends React.Component {
constructor(props){
super(props);
}
render(){
// ...
}
}
Your container component is supposed to be a component and it must have a render function with the dumb/presentational components you want to render.
import { connect } from 'react-redux';
import LoginPage from "../login/LoginPage";
import UserActions from "../users/UserActions";
class LoginContainer extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<LoginPage userData={this.props.userData}
onSuccessfulLogin={this.props.onSuccessfulLogin}
/>
)
}
};
const mapDispatchToProps = (dispatch) => {
return {
onSuccessfulLogin: (userData) => {
dispatch(UserActions.userLoggedIn(userData))
}
}
}
const mapStateToProps = (state) => {
return {
userData: state.userData
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(LoginPage);