I'm creating a module named isMember. This module should be able to check if state.current_user.member is true or not.
1 import { select } from "redux-saga/effects"
2
3 export function* isMember() {
4 const { member } = yield select((state: any) => state.current_user)
5 console.log("isMember: ", member)
6 return member
7 }
I'm trying to test it like this in my view:
import { isMember } from "../utils/isMember"
return (
{ isMember() && <span> is a member </span> }
)
But that yields this error:
select is an Effect object of redux-saga. It is a tool to handle redux's side effects and should be used exclusively in a saga.
Generally, to test your module, you need to put it in a saga watcher that watches over an action:
import { takeEvery } from 'redux-saga'
function* watchTestingAction() {
yield takeEvery(TESTING_ACTION_TYPE, isMember)
}
and dispatch that action in React component:
import { connect } from 'react-redux'
...
return (
<MainContainer withScroll>
<GjeButton
title="isMember?"
onPress={this.props.testingAction} />
...
const mapState = (state) => ({})
const mapDispatch = (dispatch) => ({
testingAction: () => dispatch({ type: TESTING_ACTION_TYPE })
})
export default connect(mapState, mapDispatch)(YourComponent)
EDIT: To get state data, redux-saga is not needed. What you need is connect from react-redux.
import React, { Component } from 'react'
import { connect } from 'react-redux'
...
class MyComponent extends Component
render() {
return (
<MainContainer withScroll>
<GjeButton
title="isMember?"
onPress={() => { console.log(this.props.isMember) }} />
)
}
}
const mapState = (state) => ({
isMember: state.current_user.member || false
})
export default connect(mapState)(YourComponent)
Related
Hi im new to redux and im trying to create a movie app using the API from www.themoviedb.org. I am trying to display the popular movies and im sure the API link works since ive tested it in postman but i cant seem to figure out why redux doesnt pick up the data.
//action
import { FETCH_POPULAR } from "./types";
import axios from "axios";
export const fetchPopularMovies = () => (dispatch) => {
axios
.get(
`https://api.themoviedb.org/3/movie/popular?api_key=${API}&language=en-US`
)
.then((response) =>
dispatch({
type: FETCH_POPULAR,
payload: response.data
})
)
.catch((err) => console.log(err));
};
//reducer
import { FETCH_POPULAR } from "../actions/types";
const initialState = {
popular: [],
};
export default function (state = initialState, action) {
switch (action.type) {
case FETCH_POPULAR:
return {
...state,
popular: action.payload,
};
default:
return state;
}
}
import React from "react";
import { connect } from "react-redux";
import Popular from "./Popular";
const FetchedPopular = (props) => {
const { popular } = props;
let content = "";
content =
popular.length > 0
? popular.map((item, index) => (
<Popular key={index} popular={item} />
))
: null;
return <div className="fetched-movies">{content}</div>;
};
const mapStateToProps = (state) => ({
popular: state.popular.popular,
});
export default connect(mapStateToProps)(FetchedPopular);
import React from "react";
import "../Styles.css";
const Popular = (props) => {
return (
<div className="movie-container">
<img
className="poster"
src={`https://image.tmdb.org/t/p/w400/${props.poster_path}`}
/>
</div>
);
};
export default Popular;
I cant really tell what I'm missing can someone help?
Next to mapStateToProps you need to create mapDispatchToProps. After that, you will be able to call your Redux action from your React component.
I suggest you the mapDispatchToProps as an Object form. Then you need to use this mapDispatchToProps as the second parameter of your connect method.
When you will have your action mapped to your component, you need to call it somewhere. It is recommended to do it for example on a component mount. As your React components are Functional components, you need to do it in React useEffect hook.
import React, { useEffect } from "react";
import { connect } from "react-redux";
import Popular from "./Popular";
import { fetchPopularMovies } from 'path_to_your_actions_file'
const FetchedPopular = (props) => {
const { popular } = props;
let content = "";
useEffect(()=> {
// call your mapped action (here it is called once on component mount due the empty dependency array of useEffect hook)
props.fetchPopularMovies();
}, [])
content =
popular.length > 0
? popular.map((item, index) => (
<Popular key={index} popular={item} />
))
: null;
return <div className="fetched-movies">{content}</div>;
};
const mapStateToProps = (state) => ({
popular: state.popular.popular,
});
// create mapDispatchToProps
const mapDispatchToProps = {
fetchPopularMovies
}
// use mapDispatchToProps as the second parameter of your `connect` method.
export default connect(mapStateToProps, mapDispatchToProps)(FetchedPopular);
Moreover, as I wrote above in my comment, your Popular does not have the prop poster_path but it has the prop popular which probably has the property poster_path.
import React from "react";
import "../Styles.css";
const Popular = (props) => {
return (
<div className="movie-container">
<img
className="poster"
src={`https://image.tmdb.org/t/p/w400/${props.popular.poster_path}`}
/>
</div>
);
};
export default Popular;
I want my function below, "VerifyEmailResend" to have access to the two dispatch methods inside of mapDispatchToProps. How do I do that?
VerifyEmailResend() is exported because i want it available to be called throughout my application.
This app is written in React using Redux.
I know normally the connect method is used, but connect is for react components specifically. Is there something similar here I am missing?
import React, { Component, Fragment } from 'react'
import { api } from '../../api'
import { bool, func } from 'prop-types'
import VerifyEmailResent from './VerifyEmailResent'
import VerifyEmailVerified from './VerifyEmailVerified'
import { connect } from 'react-redux'
class VerifyEmail extends Component {
static propTypes = {
// has the verify email been resent \\
verifyEmailResent: bool,
// have you already verified your email \\
verifyEmailVerified: bool,
// set status of verify email \\
onSetVerifyEmailResent: func.isRequired,
// set status of the email verified \\
onSetVerifyEmailVerified: func.isRequired
}
resent = () => {
const { onSetVerifyEmailResent } = this.props
onSetVerifyEmailResent(false)
}
verified = () => {
const { onSetVerifyEmailVerified } = this.props
onSetVerifyEmailVerified(false)
}
render() {
const { verifyEmailResent, verifyEmailVerified } = this.props
return (
<Fragment>
{verifyEmailResent && (
<VerifyEmailResent action={this.resent} />
)}
{verifyEmailVerified && (
<VerifyEmailVerified action={this.verified} />
)}
</Fragment>
)
}
}
const mapStateToProps = state => ({
verifyEmailResent: state.eventListenerState.verifyEmailResent,
verifyEmailVerified: state.eventListenerState.verifyEmailResent
})
const mapDispatchToProps = dispatch => ({
onSetVerifyEmailResent: verifyEmailResent =>
dispatch({ type: 'VERIFY_EMAIL_RESENT_SET', verifyEmailResent }),
onSetVerifyEmailVerified: verifyEmailVerified =>
dispatch({ type: 'VERIFY_EMAIL_RESENT_VERIFIED', verifyEmailVerified })
})
const VerifyEmailResend = () => () => {
api.user.resendEmailVerification().then(data => {
if (data.resent) {
//onSetVerifyEmailResent(true)
}
if (data.verified) {
//onSetVerifyEmailVerified(false)
}
})
}
export connect(null, mapDispatchToProps)(VerifyEmailResend)
export default connect(
mapStateToProps,
mapDispatchToProps
)(VerifyEmail)
I am not sure what you're confused at. But you can do it:
const VerifyEmailResend = () => {}
export default connect(null, mapDispatchToProps)(VerifyEmailResend)
As per you need a named export, you can do it like:
export {
VerifyEmailResend: connect(null, mapDispatchToProps)(VerifyEmailResend)
}
And you can import it normally like:
import { VerifyEmailResend } from '..'
And as per your comment, you can call it like followings depending your need of field:
{ VerifyEmailResend() }
Or like:
<VerifyEmailResend />
I have a simple component I'm trying to make work with redux. I map both props and dispatch actions, however only the props I initially get from the store work properly. I traced it all down to my actions: they are being dispatched, but respective reducers don't really do anything. Pretty simple stuff I came up with according to the tutorial and everything looks good to me, but I can't wrap my head around the problem here.
Here is a simplified version of the app:
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Search from './Search'
import { Provider } from 'react-redux'
import store from './store'
const root = document.querySelector('#app')
ReactDOM.render(
<Provider store={store}>
<Search/>
</Provider>, root)
// Search.js
import React from 'react'
import { setText } from '../../actions/appActions'
import { connect } from 'react-redux';
const mapStateToProps = state => {
return {
text: state.app.searchText
}
}
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
class Search extends React.Component {
constructor() {
super()
}
render() {
return (
<input type="text" onChange={() => this.props.setText("text")} value={this.props.text}/>
)
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Search)
// store.js
import { createStore, combineReducers } from 'redux'
import app from './reducers/appReducer'
export default createStore(combineReducers({/*other non-relevant reducers*/, app}))
// appActions.js
export function setText(text) {
return {
type: "APP_SET_TEXT",
payload: text,
}
}
// appReducer.js
const initialState = {
isSearchActive: true,
searchText: "Text",
}
export default function reducer(state = initialState, action) {
switch (action.type) {
case "APP_SET_TEXT":
console.log("fart")
return {
...state,
searchText: action.payload,
}
default:
return state
}
}
What I'm trying to to is to simply make the input value change according to the redux state. I do get the text from {this.props.text}, the change handler onChange={() => this.props.setText("text")} is being dispatched, but the reducer for some reason fails to catch the action that was dispatched.
I think you should change the mapDispatchToProps variable like the following:
const mapDispatchToProps = dispatch => {
return {
setText = (text) => dispatch(setText(text)),
}
}
There are two ways to achieve this
// MODIFYING DISPATHCER
const mapDispatchToProps = dispatch => {
return {
changeText: data => dispatch(setText(data)),
}
}
or
// CONNECT
export default connect(mapStateToProps, {
setText
})(Search)
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
change to
const mapDispatchToProps = dispatch => {
return {
changeText: text => dispatch(setText(text)),
}
}
And in your component use this.props.changeText function
as most of the answers suggests you can dispatch the actions or else you can simply have mapDispatchToProps an object.
mapDispatchToProps = {
setText,
dispatch
}
Your HOC connect should take care of dispatching not need to external definition
Use bindActionCreators from redux
import { bindActionCreators } from 'redux';
const mapDispatchToProps = dispatch => {
const setText = bindActionCreators(setText, dispatch);
return setText;
}
Since you're mapping your dispatch to props like this:
const mapDispatchToProps = dispatch => {
return {
setText,
dispatch
}
}
You'll need to explicitly call dispatch in your component:
class Search extends React.Component {
constructor() {
super()
}
render() {
const {dispatch, setText} = this.props;
return (
<input type="text" onChange={() => dispatch(setText("text"))} value={this.props.text}/>
)
}
}
It is easier just to map dispatch to props like this: setText = (text) => dispatch(setText(text))
Dispatch in component is UNDEFINED and dispatch in mapDispatchToProps is ok
Action and reducers is ok - 100%;
I want transfer to dispatch in action to create request and run action from action
My component:
import React, { Component, Fragment } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import styled from 'styled-components';
import { carAction, fetchDogAction } from '../../../actions/CarAction';
class CarListContainer extends Component {
render () {
const { cars, carAction, dispatch, dog } = this.props;
console.log(dispatch) // THIS UNDEFINED!!!!
return(
<Fragment>
<Title onClick={() => {
fetchDogAction(dispatch)
}}>HEllo</Title>
{cars.map((elem) =>
<Title onClick={() => {carAction (elem)}} key={elem.id}>{elem.mark}</Title>
)}
{dog ? <img src={dog.message} /> : null }
</Fragment>
)
}
}
const Title = styled('h2')`
color: red;
font-size: 30px;
`;
function mapStateToProps (state) {
return {
cars: state.cars,
dog: state.dog
}
}
function mapDispatchToProps(dispatch) {
console.log(dispatch) //THIS DISPATCH IS OK
return bindActionCreators ({
carAction: carAction,
fetchDogAction: fetchDogAction
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(CarListContainer);
Your error comes from having bindActionCreators() inside mapDispatchToProps() which is not recommended practice, since mapDispatchToProps uses bindActionCreators internally.
bindActionCreators and mapDispatchToProps - Do I need them?
You can try using an arrow function and dispatching actions directly in the mapDispatchToProps method.
import * ACTIONS from './actions'
function mapDispatchToProps(dispatch) {
return {
carAction: (elem) => dispatch(ACTIONS.fetchCarAction(elem)) ,
dogAction: () => dispatch(ACTIONS.fetchDogAction())
}
}
//action creators import them into your component
export const fetchCarAction = (elem) => {
return {
type: ACTION_TYPES.CARACTION,
payload: elem
}
}
export const fetchDogAction = () => {
return {
type: ACTION_TYPES.DOGACTION,
}
}
//render method
<Title onClick={() => this.props.dogAction() }>HEllo</Title>
{cars.map((elem) =>
<Title onClick={() => this.props.carAction(elem) } key={elem.id}>{elem.mark}
</Title>
)}
So in your render you will call the name of the property in mapDispatchToProps and not the name of the action creator, I kept the name of the action creators and name of the properties different so you can see this.
If you want a fully functioning react-redux app you can check out this starter project I built, I got good feedback on it.
https://github.com/iqbal125/modern-react-app-sample
I am new to React/Redux, and appreciate your help. I am taking a Udemy course on this topic. The course instructor creates a component like this.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUser } from '../actions';
class User extends Component {
componentDidMount(){
this.props.fetchUser(this.props.userId);
}
render(){
const { user } = this.props;
if(!user) return null;
return(
<div className="header"> User Info: {user.name}</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return { user: state.users.find( user => user.id === ownProps.userId)};
};
export default connect(mapStateToProps, { fetchUser })(User)
my question: why inside the componentDidMount() he is prefixing fetchUsers() with this.props?
it is not the case that he is passing fetchUsers() as props from the parent component. This is how the parent is using this component <User userId={post.userId}/>
Note: this code works
It is because of this line :
export default connect(mapStateToProps, { fetchUser })(User)
the second parameter to connect is called mapDispatchToProps, It adds the actions to props
From the docs :
connect can accept an argument called mapDispatchToProps, which lets
you create functions that dispatch when called, and pass those
functions as props to your component.
const mapDispatchToProps = dispatch => {
return {
// dispatching plain actions
increment: () => dispatch({ type: 'INCREMENT' }),
decrement: () => dispatch({ type: 'DECREMENT' }),
reset: () => dispatch({ type: 'RESET' })
}
}
Your code is using the “object shorthand” form.
The way the mapDispatchToProps in the example is shorthanded. It might be easier to tell what is going if it was written like so:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUser } from '../actions';
class User extends Component {
componentDidMount(){
this.props.fetchUser(this.props.userId);
}
render(){
const { user } = this.props;
if(!user) return null;
return(
<div className="header"> User Info: {user.name}</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
return { user: state.users.find( user => user.id === ownProps.userId)};
};
const mapDispatchToProps = () => ({
fetchUser
});
export default connect(mapStateToProps, mapDispatchToProps)(User)
Maybe this shows it more clearly, but the dispatch function (fetchUser) is being mapped to the components properties. Just like the state value (user) is being mapped to the properties of the component. I think you just got confused because of the shorthand that was used.