Reputation: 101
Trying to implement redux into one of my existing apps (for the first time). Essentially trying to do something quite simple, use a text input to store a string in the store and relay it back in another component using redux. However although the action dispatches, when I log it to the console, I keep getting 'undefined' for the entered string. Not sure where I'm going wrong and other questions aren't making it much clearer for my beginners mind!
I've defined singular reducers, combined them in an index, created the store (passing my combined reducer), wrapped navigation (entire app) in a provider with my store, created a dispatch and event/action to activate the dispatch (basically when the user enters a character and they press a continue button).
textInputPost.js: (Reducer)
const initialState = {
textInputValue: '',
};
const textInputReducer = (state = initialState, action) => {
console.log('textInputReducer', action);
switch(action.type){
case 'ADD_INPUT_TEXT':
return { textInputValue: action.text };
case 'RESET_INPUT_TEXT':
return { textInputValue: ''}
default:
return state;
}
}
export default textInputReducer;
index.js: (rootReducer - combine reducers)
import { combineReducers } from 'redux';
import photoInputPost from './photoInputPost'
import cameraInputPost from './cameraInputPost'
import textInputPost from './textInputPost'
export default rootReducer = combineReducers({
text: textInputPost
})
Index.js: (Store)
import { createStore } from 'redux'
import rootReducer from './../reducers/index'
export default Store = createStore(rootReducer)
App.js: (Provider wrapped around React Navigation)
return (
<Provider store={Store}>
<Navigation/>
</Provider>
);
AddTextModal.js: (Component for updating store state on textInput)
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, KeyboardAvoidingView, TextInput } from 'react-native';
import { AntDesign } from '@expo/vector-icons';
import { createAppContainer, createSwitchNavigator } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createBottomTabNavigator } from 'react-navigation-tabs';
import { FontAwesome5, Feather } from "@expo/vector-icons";
import { connect } from 'react-redux'
import ModalContainer from '../../App'
class AddTextModal extends React.Component {
continueUpload = (textInput) => {
this.props.addText(textInput)
console.log(this.props.textInputValue)
this.props.navigation.navigate('Upload')
}
render() {
return(
<View style={{backgroundColor:"#000000CC", flex:1}}>
<View style={{ backgroundColor:"#ffffff", marginLeft: 0, marginRight: 0, marginTop: 180, padding: 20, borderTopLeftRadius: 20, borderTopRightRadius: 20, flex: 1, }}>
<View style={styles.header}>
<TouchableOpacity style={{position: 'absolute'}} onPress={() => this.props.navigation.navigate('Home')}>
<Text style={styles.buttonFont}>Back</Text>
</TouchableOpacity>
<Text style={styles.headerText}>Write Something</Text>
<TouchableOpacity style={{position: 'absolute', right: 0}} onPress={(textInput) => this.continueUpload(textInput)}>
<Text style={styles.buttonFont}>Continue</Text>
</TouchableOpacity>
</View>
<View style={styles.uploadTextInput}>
<Feather name="message-square" size={14} color="grey" />
<TextInput style={{paddingLeft: 5, fontSize: 14}}
placeholder="What do you want to say?"
defaultValue={this.props.textInputValue}
onChangeText={textInput => this.props.addText(textInput)}
/>
</View>
</View>
</View>
);
}
}
//#6 mapStateToProps to access store from our component
function mapStateToProps(state){
return {
textInputValue: state.textInputValue
}
}
//#10. matchDispatchertoProps to establish dispatcher for actions. These actions will then go to functions in the reducer to change the app state
function mapDispatchToProps(dispatch) {
return {
addText: () => dispatch({type: 'ADD_INPUT_TEXT'}),
}
}
UploadScreen.js: (Component for relaying store state of text Input of AddTextModal)
import React from 'react';
import { Text, Image, View, TextInput, TouchableHighlight, TouchableOpacity } from 'react-native';
import { FontAwesome5, Feather } from "@expo/vector-icons";
import { connect } from 'react-redux'
import ToolbarComponent from './ToolbarComponent'
import styles from './../Styles';
import textInput from './../../containers/textInput'
class UploadScreen extends React.Component {
uploadMedia = () => {
//upload to DB - add to vault, home screen
this.props.resetText()
this.props.navigation.navigate('Home')
}
//viewPhoto function for viewing photo on full screen
viewPhoto = () => {
return
}
render() {
return(
<View style={{backgroundColor:"#000000CC", flex:1}}>
<View style={{ backgroundColor:"#ffffff", marginLeft: 0, marginRight: 0, marginTop: 180, padding: 20, borderTopLeftRadius: 20, borderTopRightRadius: 20, flex: 1, }}>
<View style={styles.header}>
<TouchableOpacity style={{position: 'absolute'}} onPress={() => this.props.navigation.goBack()}>
<Text style={styles.buttonFont}>Back</Text>
</TouchableOpacity>
<TouchableOpacity style={{position: 'absolute', right: 10}} onPress={() => this.uploadMedia()}>
<Text style={styles.buttonFont}>Upload</Text>
</TouchableOpacity>
<View style={styles.uploadTextInput}>
<Text>{this.props.textInputValue}</Text>
</View>
</View>
</View>
</View>
);
}
}
function mapStateToProps(state){
return {
textInputValue: state.textInputValue
}
}
function mapDispatchToProps(dispatch) {
return {
resetText:() => dispatch({type: 'RESET_INPUT_TEXT'})
}
}
export default connect(mapStateToProps, mapDispatchToProps)(UploadScreen);
Upvotes: 1
Views: 789
Reputation: 671
I believe your issue is that you haven't specified a payload in your mapDispatchToProps function. Try re-writing your mapDispatchToProps function to look something like:
function mapDispatchToProps(dispatch) {
return {
addText: (payload) => dispatch({type: 'ADD_INPUT_TEXT', payload: payload}),
}
}
And since I renamed your payload, 'payload', change 'action.text' to 'action.payload' in your reducer:
const initialState = {
textInputValue: '',
};
const textInputReducer = (state = initialState, action) => {
console.log('textInputReducer', action);
switch(action.type){
case 'ADD_INPUT_TEXT':
return { textInputValue: action.payload };
case 'RESET_INPUT_TEXT':
return { textInputValue: ''}
default:
return state;
}
}
export default textInputReducer;
Upvotes: 1