I am trying to use redux in my app for the first time and i set up whole boilerplate for it but i got an error which says Error: The slice reducer for key "AuthReducer" returned undefined during initialization. as it says i checked the state value passed in reducer but i can't figure it out, Here i am adding my code sample.
reducer.js
import {combineReducers} from 'redux'
import { SIGN_IN, SIGN_OUT, SIGN_UP, MOVIE_ADDED, MOVIE_REMOVED } from './ActionTypes'
const initialMovieState = {
savedMovies: [
{
id: '',
name: ''
}
]
}
const initialAuthState = {
userEmail: '',
userPassword: '',
userToken: '',
}
export const AuthReducer = (state=initialAuthState, action) => {
switch (action.type) {
case SIGN_IN:
return {
...state,
userToken: action.payload.token
}
case SIGN_UP:
return {
...state,
userEmail: action.payload.email,
userPassword: action.payload.password
}
case SIGN_OUT:
return {
...state,
userToken: ''
}
default:
state
}
}
export const MovieReducer = (state=initialMovieState, action) => {
switch (action.type) {
case MOVIE_ADDED:
return {
...state,
savedMovies: state.savedMovies.concat({
id: action.payload.movieId,
name: action.movieName
})
}
case MOVIE_REMOVED:
return state.filter(movie => movie.id !== action.payload.movieId)
default:
state
}
}
const RootReducer = combineReducers({
AuthReducer,
MovieReducer
})
export default RootReducer
actions.js
import {SIGN_IN, SIGN_OUT, SIGN_UP, MOVIE_ADDED, MOVIE_REMOVED} from './ActionTypes'
export const sign_in = (user) => (
{
type: SIGN_IN,
payload: {
token: user
}
}
)
export const sign_up = (user) => (
{
type: SIGN_UP,
payload: {
email: user.email,
password: user.password
}
}
)
export const sign_out = () => (
{
type: SIGN_OUT,
}
)
export const movie_added = (movie) => (
{
type: MOVIE_ADDED,
payload: {
movieId: movie.id,
movieName: movie.name,
}
}
)
export const movie_removed = () => (
{
type: MOVIE_REMOVED
}
)
store.js
import { createStore } from 'redux'
import {composeWithDevTools} from 'redux-devtools-extension'
import rootReducer from './Reducer'
const Store = createStore(rootReducer, composeWithDevTools())
export default Store
I've wrapped the whole app in Provider with store as an argument in App.js
SignUpScreen.js
import {useDispatch, useStore} from 'react-redux'
import {sign_up} from '../redux/Actions'
const SignUpScreen = () => {
const navigation = useNavigation()
const dispatch = useDispatch()
const Store = useStore()
...
const handleSubmit = () => {
if(isValidEmail === true && isValidPass === true && isPassMatched === true){
console.log(Store.getState())
dispatch(sign_up({email: email, password: password}))
console.log(Store.getState())
navigation.navigate('signin')
ToastAndroid.showWithGravity(
'Account created.',
ToastAndroid.LONG,
ToastAndroid.BOTTOM
)
} else {
ToastAndroid.showWithGravity(
'Invalid Email or Password',
ToastAndroid.LONG,
ToastAndroid.BOTTOM
)
}
}
...
return(
{/* register button */}
<TouchableOpacity style={styles.regBtnCont} onPress={() => handleSubmit()}>
<Text style={styles.regBtnText}>Register</Text>
</TouchableOpacity>
)
}
Any help will be appriciated, Thank you.
Related
I'm having problems filtering info consummed by an api. it is actually the nasa api.
What I Want
Look photos by
Rover's Name (input)
by camera name (input)
by date
I successfully completed the last task but the first input is not bringing the image if I look by the rovers name
Search filter
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { getPhotos } from "../../redux/actions/getPhotos";
import { ErrorAlert } from "./Alerts";
import './SecondFinder.css';
export default function SecondFinder() {
const dispatch = useDispatch();
const [term, setSearchTerm] = useState("");
const [alertERR, setAlertERR] = useState(false);
const submitHandler = (e) => {
e.preventDefault();
dispatch(getPhotos(term));
}
return (
<form onSubmit={submitHandler}>
<div className="searchPhotosByRover">
<label>Search by Rovers Name</label>
<input type="text" placeholder="Search by Rover" value={term} onChange={(e) => setSearchTerm(e.target.value)} />
<button className="btn-primary">Search</button>
{alertERR ? <ErrorAlert /> : ""}
</div>
</form>
)
}
Component:
import React from "react";
import { useSelector } from "react-redux";
import { LoadingAlert, PhotoNotFoundAlert } from "./Alerts";
import Photos from "./Photos";
export default function GridPhotos() {
const state = useSelector((state) => state.result);
const renderPhotos = () => {
if (state.loading) {
return <LoadingAlert />;
} if (state.photos.length === 0) {
return <PhotoNotFoundAlert />;
}
return state.photos.map((photo, index) => {
return <Photos key={index} photo={photo} index={index} />;
});
};
return <div className="gridPhotos">{renderPhotos()}</div>;
}
Actions:
import axios from "axios";
export const getPhotos = (date, term) => async (dispatch, getState) => {
dispatch({
type: "FETCH_PHOTOS_REQUEST"
})
try {
const response = await axios.get(`https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?earth_date=${date}&name=${term}&api_key=${process.env.REACT_APP_API_KEY}&page=1`)
dispatch({
type: "FETCH_PHOTOS_SUCCESS",
payload: response.data.photos
})
} catch (error) {
dispatch({
type: "FETCH_PHOTOS_FAILURE",
error
})
}
}
Reducer
const initialState = {
photos: [],
loading: false,
error: null
}
export const getPhotosReducer = (state = initialState, action) => {
console.log("action", action)
switch (action.type) {
case "FETCH_PHOTOS_REQUEST":
return {
...state,
loading: true,
error: null
}
case "FETCH_PHOTOS_SUCCESS":
return {
...state,
loading: false,
photos: action.payload
}
case "FETCH_PHOTOS_FAILURE":
return {
...state,
loading: false,
error: action.error,
photos: []
}
default:
return state
}
}
I just want to look by the rovers name and bring a picture based on this name
enter image description here
i've been having troble getting my nextjs app to work with getServerSideProps() for server-side-rednering. i tried implemening next-redux-wrapper but the state is empty.
*note: redux works fine while it was running on client side, but now im trying to get the state in getServerSideProps() and pass it into the component, so it renders on the server.
store.js:
const reducer = combineReducers({
productList: productListReducer,
categoryList: categoryListReducer,
})
const middleware = [thunk]
const makeStore = context => createStore(reducer, composeWithDevTools(applyMiddleware(...middleware)))
const wrapper = createWrapper(makeStore, {debug: true})
export default wrapper
reducer.js:
export const productListReducer = (state = { products: [] }, action) => {
switch (action.type) {
case HYDRATE:
return {...state, ...action.payload}
case 'PRODUCT_LIST_REQUEST':
return { loading: true, products: [] }
case 'PRODUCT_LIST_SUCCESS':
return { loading: false, products: action.payload }
case 'PRODUCT_LIST_FAIL':
return { loading: false, error: action.payload }
default:
return state
}
}
_app.js:
import wrapper from '../redux/store'
function MyApp({ Component, pageProps }) {
return (
<Component {...pageProps} />
)
}
export default wrapper.withRedux(MyApp)
index.js:
import wrapper from '../redux/store'
export const getServerSideProps = wrapper.getServerSideProps(store => ({req, res}) => {
const state = store.getState()
const { products } = state.productList
return {props: {products: products}}
})
export default function Home({products}) {
return (
<>
<div>{products}</div>
</>
)
}
page.js:
const mapDispatchToProps = (dispatch) => {
return {
listProducts: bindActionCreators(listProducts, dispatch),
listCategories: bindActionCreators(listCategories, dispatch)
}
}
function mapStateToProps(state) {
return {
products: state.productList.products,
loading: state.productList.loading,
categories: state.categoryList.categories,
loadingCategory: state.categoryList.loading
}
}
CategoryScreen.getInitialProps = wrapper.getInitialPageProps((store) => async () => {
await store.dispatch(listProducts())
await store.dispatch(listCategories())
})
export default connect(mapStateToProps, mapDispatchToProps)(CategoryScreen)
reducer.js:
import { HYDRATE } from "next-redux-wrapper"
export const categoryListReducer = (state = { categories: [] }, action) => {
switch (action.type) {
case HYDRATE:
return {...state, ...action.payload}
case 'CATEGORY_LIST_REQUEST':
return { loading: true, categories: [] }
case 'CATEGORY_LIST_SUCCESS':
return { loading: false, categories: action.payload }
case 'CATEGORY_LIST_FAIL':
return { loading: false, error: action.payload }
default:
return state
}
}
store.js:
const combinedReducer = combineReducers({
productList: productListReducer,
categoryList: categoryListReducer
})
const reducers = (state, action) => {
if (action.type === HYDRATE) {
const nextState = {
...state,
...action.payload
}
return nextState
} else {
return combinedReducer(state, action)
}
}
const bindMiddleware = (middleware) => {
if (process.env.NODE_ENV !== 'production') {
const { composeWithDevTools } = require('redux-devtools-extension')
return composeWithDevTools(applyMiddleware(...middleware))
}
return applyMiddleware(...middleware)
}
export const makeStore = (context) => {
const store = createStore(reducers, bindMiddleware([thunk]))
return store
}
export const wrapper = createWrapper(makeStore, { debug: true })
I want to create a login page. When I enter value to textInput(Email or password) on emulator, it returns INITIAL_STATE(empty string) constantly. And render() in Login.js does not re-render when I enter any input. If I change for instance email, EMAIL_CHANGED case in LoginReducer.js activated but cannot change the state. No error on debugger console. How could I solve this problem?
Main.js
render() {
const store = createStore(reducers, {}, applyMiddleware(ReduxThunk));
return (
<Provider store={store}>
<Login />
</Provider>
);}}
Login.js
render(){
const {containerStyle, subContainerStyle, inputStyle} = styles;
return(
<View style={containerStyle}>
<View style={subContainerStyle}>
<TextInput
placeholder="E-mail"
style={inputStyle}
value={this.props.email}
onChangeText={email => this.props.emailChanged(email)}
/>
</View>
<View style={subContainerStyle}>
<TextInput
secureTextEntry
placeholder="Password"
style={inputStyle}
value={this.props.password}
onChangeText={password => this.props.passwordChanged(password)}
/>
</View>
<View style={subContainerStyle}>
{this.renderLoginButton()}
</View>
</View>
);}}
const mapStateToProps = state => {
return {
email: state.auth.email,
password: state.auth.password,
loading: state.auth.loading
};
};
export default connect(mapStateToProps, { emailChanged, passwordChanged,loginWithEmail })(Login);
LoginReducer.js
import { EMAIL_CHANGED, PASSWORD_CHANGED, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL } from '../actions/types';
const INITIAL_STATE = {
email: '',
password: '',
loading: false
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EMAIL_CHANGED:
console.log(state.email);
return { ...state, email: action.payload };
case PASSWORD_CHANGED:
return { ...state, password: action.payload };
case LOGIN_USER:
return { ...state, loading: true };
case LOGIN_USER_SUCCESS:
return { ...state, loading: false };
case LOGIN_USER_FAIL:
return { ...state, loading: false };
default:
return { ...state };
}
};
reducers/index.js
import { combineReducers } from 'redux';
import LoginReducer from './LoginReducer';
export default combineReducers({
auth: LoginReducer
});
types.js
export const EMAIL_CHANGED = 'email_changed';
export const PASSWORD_CHANGED = 'password_changed';
export const LOGIN_USER = 'login_user';
export const LOGIN_USER_SUCCESS = 'login_user_succes';
export const LOGIN_USER_FAIL = 'login_user_fail';
loginActions.js
import { EMAIL_CHANGED, PASSWORD_CHANGED, LOGIN_USER, LOGIN_USER_SUCCESS, LOGIN_USER_FAIL } from './types';
export const emailChanged = (email) => {
return (dispatch) => {
dispatch({
type: EMAIL_CHANGED,
payload: email
});
};
};
export const passwordChanged = (password) => {
return (dispatch) => {
dispatch({
type: PASSWORD_CHANGED,
payload: password
});
};
};
Your issue is that you are not passing the email and password to thunks.
const mapDispatchToProps = (dispatch) => {
return {
emailChanged: (email) => {
dispatch(emailChanged(email))
},
passwordChanged: (password) => {
dispatch(passwordChanged(password))
},
loginWithEmail: () => {
// TODO: complete this yourself, as you did not provide what it is in your code.
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
How can I fetch only one data and write it to Header ?
I am using firebase and react-redux.
firebase structure i try to write "organization": inovanka:
Action File Codes:
import firebase from 'firebase';
import { Actions } from 'react-native-router-flux';
import { ORGANIZATION_NAME_DATA_SUCCESS } from './types';
export const organizationName = () => {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/organizations/${currentUser.uid}`)
.on('value', snapshot => {
dispatch({ type: ORGANIZATION_NAME_DATA_SUCCESS, payload: snapshot.val() });
});
};
}
Reducer File :
import { ORGANIZATION_NAME_DATA_SUCCESS } from '../actions/types';
const INITIAL_STATE = {
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ORGANIZATION_NAME_DATA_SUCCESS:
console.log(action); // data retrieved as array
return action.payload
default:
return state;
}
};
Component: (I would like to write it to this)
class HomePage extends Component {
componentWillMount() {
}
render() {
return (
<Container>
<Header>
<Text> i would like to write it here </Text>
</Header>
<Content>
</Content>
</Container>
);
}
}
const mapStateToProps = ({ homepageResponse }) => {
const organizationArray = _.map(homepageResponse, (val, uid) => {
return { ...val, uid }; //
});
return { organizationArray };
};
export default connect(mapStateToProps, { organizationName })(HomePage);
Change this:
firebase.database().ref(`/organizations/${currentUser.uid}`)
.on('value', snapshot => {
to this:
firebase.database().ref(`/organizations/${currentUser.uid}`)
.once('value', snapshot => {
using once() will read data only one time, thus fetching only one data
Solution is Here !
Action File:
export const organizationName = () => {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/organizations/${currentUser.uid}`)
.once('value', snapshot => {
_.mapValues(snapshot.val(), o => {
console.log(o);
dispatch({ type: ORGANIZATION_NAME_DATA_SUCCESS, payload: {organization: o.organization, fullname: o.fullname }});
});
});
};
}
Reducer File
const INITIAL_STATE = {
organization: '',
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ORGANIZATION_NAME_DATA_SUCCESS:
console.log(action);
return {...state, organization:action.payload.organization };
default:
return state;
}
};
Component File MapToStateProps and componentWillMount
const mapStateToProps = state => {
const { organization, fullname } = state.homepageResponse;
console.log("burada" + organization);
return { organization, fullname };
};
componentWillMount(){
this.props.organizationName();
}
*Last Step Header *
render() {
return (
<Container>
<Header>
<Text> { this.props.organization } </Text>
</Header>
</Container>
}
Thank You Everyone
I am trying to implement the following example in my project:
https://github.com/reactjs/redux/tree/master/examples/async
But I keep running into the error: dispatch is not function
when executing the dispatch function from my actions class.
It seems as if Dispatcher is not getting passed down to my actions but I followed the flow in the example:
actions/index.js file:
export const REQUEST_LOCAL_POSTS = 'REQUEST_LOCAL_POSTS';
export const RECEIVE_LOCAL_POSTS = 'RECEIVE_LOCAL_POSTS';
export const REQUEST_CURRENT_LOCATION = 'REQUEST_CURRENT_LOCATION';
export const RECEIVE_CURRENT_LOCATION = 'RECEIVE_CURRENT_LOCATION';
export const requestCurrentLocation = () => ({
type: REQUEST_CURRENT_LOCATION
})
export const receiveCurrentLocation = currentLocation => ({
type: RECEIVE_CURRENT_LOCATION,
currentLocation,
receivedCurrentLocationAt: Date.now()
})
export const requestLocalPosts = () => ({
type: REQUEST_LOCAL_POSTS
})
export const receiveLocalPosts = json => ({
type: RECEIVE_LOCAL_POSTS,
posts: json,
receivedAt: Date.now()
})
export const fetchLocalPosts = dispatch => {
dispatch(requestCurrentLocation())
navigator.geolocation.getCurrentPosition(
(position) => {
dispatch(requestLocalPosts()) // getting dispatch is not a function here
return fetch(`http://192.168.1.3:9000/posts?lng=${position.coords.longitude}&lat=${position.coords.latitude}&radius=1000`)
.then(response => response.json())
.then(json => dispatch(receiveLocalPosts(json)))
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
)
home.js (component):
import React, { Component } from 'react';
import {Text, View, ActivityIndicator, FlatList, Image, TouchableHighlight} from 'react-native';
import styles from './styles';
import MapView from 'react-native-maps';
import images from '../../config/images';
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { fetchLocalPosts } from '../../actions'
class Home extends Component {
static navigationOptions = ({ navigation }) => {
//const {dispatch , state, setParams} = navigation;
return {
title:<Text style={styles.title}>Localized</Text>,
headerStyle: {backgroundColor: '#2c6da4'},
headerRight: (
<TouchableHighlight onPress={() => navigation.dispatch({ type: 'MAP_EXPLORE' })}>
<Image
source={images.icons.map}
/>
</TouchableHighlight>
),
};
};
static propTypes = {
posts: PropTypes.array.isRequired,
isFetching: PropTypes.bool.isRequired,
lastUpdated: PropTypes.number,
dispatch: PropTypes.func.isRequired
}
componentDidMount() {
console.log(this.props)
const { dispatch } = this.props
dispatch(fetchLocalPosts()) // calling action from here
}
render() {
return (
<View style={styles.container}>
// i know posts isnt accessed here yet, still trying
to get past error
<FlatList
data={this.state.data}
refreshing={this.state.refreshing}
showsVerticalScrollIndicator={false}
ListHeaderComponent={this.renderHeader}
onRefresh={this._onRefresh.bind(this)}
renderItem={({item}) => <View><FlatList
data={item.posts}
horizontal={true}
snapToAlignment='center'
showsHorizontalScrollIndicator={false}
renderItem={({item}) => <Text style={styles.item}>{item.title}{"\n"}{item.snippet}</Text>}/>
<Text style={styles.subItem}>{item.Name}{"\n"}{item.Address}</Text>
</View>}
/>
</View>
);
}
}
const mapStateToProps = state => {
const { postsByBusiness } = state
const {
isFetching,
lastUpdated,
items: posts
} = postsByBusiness || {
isFetching: true,
items: []
}
return {
posts,
isFetching,
lastUpdated
}
}
export default connect(mapStateToProps)(Home)
reducer/index.js:
import { combineReducers } from 'redux';
import { NavigationActions } from 'react-navigation';
import { AppNavigator } from '../navigators/AppNavigator';
import { RECEIVE_LOCAL_POSTS, REQUEST_LOCAL_POSTS } from '../actions';
const initialNavState=AppNavigator.router.getStateForAction(NavigationActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName: 'Home',
}),
],
}));
const MAP_EXPLORE = 'MAP_EXPLORE';
const LIST_EXPLORE = 'LIST_EXPLORE';
function nav(state = initialNavState, action) {
let nextState;
switch(action.type) {
case MAP_EXPLORE:
nextState = AppNavigator.router.getStateForAction(
NavigationActions.navigate({ routeName: 'Map'}),
state
);
break;
case LIST_EXPLORE:
nextState = AppNavigator.router.getStateForAction(
NavigationActions.navigate({ routeName: 'List'}),
state
);
break;
default:
nextState = AppNavigator.router.getStateForAction(action, state);
break;
}
return nextState || state;
}
function postsByBusiness(state = { }, action) {
switch(action.type) {
case RECEIVE_LOCAL_POSTS:
return {
...state,
isFetching: false,
didInvalidate: false,
items: action.posts,
lastUpdated: action.receivedAts
}
default:
return state
}
}
const AppReducer = combineReducers({
nav,
postsByBusiness
});
export default AppReducer;
fetchLocalPosts should be returning a function that takes dispatch as an argument. Changing it to the following should fix it.
export const fetchLocalPosts = () => dispatch => {
...
It's another way of doing this:
export const fetchLocalPosts = () => {
return function (dispatch) {
...