我遇到的具体错误因我所做的更改而异,但是,我当前遇到的错误是“动作可能没有未定义的类型...”。我对使用Redux并不陌生,但是我一直在互联网上搜寻任何足以让我遵循的内容。
TLDR:我要做的只是发送一个类似于以下内容的对象列表:记录:[{date:blah,....,var:blah},{...}] 到全局状态,这样我就可以在整个应用程序的所有部分中使用它。
我曾尝试以各种方式更改mapDispatchToProps方法,但尝试连接所有方法仍然很困难。
我尝试修改App.js,并相应地修改动作,reduce和存储文件,但它们似乎都与我所遵循的教程相同。此处显示:https://www.youtube.com/watch?v=KcC8KZ_Ga2M
以下是所有相关代码:
App.js '''
import React, { Component } from 'react';
import {
createStackNavigator,
createAppContainer } from 'react-navigation';
import MainScreen from './screens/MainScreen';
import CostAnalysis from './screens/CostAnalysis';
import DriverLog from './screens/DriverLog';
// REDUX IMPORTS
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import { recordReducer } from './reducers/recordReducer';
const MainNavigator = createStackNavigator({
Home: {screen: MainScreen,
navigationOptions: {
header: null,
}},
CostAnalysis: {screen: CostAnalysis},
DriverLog: {screen: DriverLog}
}, {
defaultNavigationOptions: {
header: null
}
});
const AppContainer = createAppContainer(MainNavigator);
const store = createStore(recordReducer);
class App extends Component {
render() {
return (
<Provider store={store}>
<AppContainer />
</Provider>
);
}
}
export default (App);
'''
我在此示例中导航至第二个屏幕并将数据发送至 '''
import React, {Component} from 'react';
import {
StyleSheet,
View,
Text,
Dimensions,
TouchableOpacity,
YellowBox,
} from 'react-native';
// REDUX IMPORTS
import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/Ionicons';
const device = Dimensions.get('window');
class CostAnalysis extends Component {
render() {
return (
<View style={styles.mainContainer}>
<Text>Hey you got here!</Text>
<Text>{this.props.records[0]}</Text>
</View>
)
}
}
const styles = StyleSheet.create({
mainContainer: {
height: device.height - 60,
position: 'absolute',
bottom: 0
}
});
function mapStateToProps(state) {
return {
records: state.records
}
}
export default connect(mapStateToProps)(CostAnalysis);
'''
MainScreen.js
'''
import React, {Component} from 'react';
import {
StyleSheet,
View,
Text,
Dimensions,
TouchableOpacity,
YellowBox,
} from 'react-native';
// REDUX IMPORTS
import { connect } from 'react-redux';
import ADD_RECORD from '../actions/types';
import {addRecord} from '../actions/index';
import Icon from 'react-native-vector-icons/Ionicons';
import LinearGradient from 'react-native-linear-gradient';
import SpecialInput from '../components/SpecialInput';
import DateTimePicker from 'react-native-modal-datetime-picker';
import SpecialText from '../components/SpecialText';
import GenericButton from '../components/GenericButton';
const devWidth = Dimensions.get('window').width;
const devHeight = Dimensions.get('window').height;
class MainScreen extends Component {
componentWillMount() {
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
// State stuff
state = {
date: 'Date',
dateColor: 'rgba(255,255,255,0.6)',
starting: '',
ending: '',
gasPriceCurrent: '',
visible: false,
}
stringifyNumbers = (inputObj) => {
return inputObj.toString().replace(/[^0-9.]/g, '')
}
handleDateConfirm = value => {
this.setState({
date: value.toString().substring(4, 15),
dateColor: 'rgba(255,255,255,1)'
});
// Hide the date picker
this.hideDatePicker();
}
handleStartChange = (value) => {
this.setState({
starting: value
});
}
handleEndChange = (value) => {
this.setState({
ending: value
});
}
handleGasChange = (value) => {
this.setState({
gasPriceCurrent: value
});
}
hideDatePicker = () => {
this.setState({
visible: false
});
}
showDateTimePicker = () => {
this.setState({
visible: true,
dateColor: 'rgba(255,255,255,0.6)'
});
}
recordEntry = () => {
const record = {
date: this.state.date,
startKM: this.state.starting,
endKM: this.state.ending,
curPrice: this.state.gasPriceCurrent
}
// This is where I try to add the record to the list
this.props.addRecord(record);
// Now go to confirmation
this.props.navigation.navigate('CostAnalysis');
// Reset input fields after recording entry
this.resetInput();
}
// Reset input fields
resetInput = () => {
this.setState({
date: 'Date',
dateColor: 'rgba(255,255,255,0.6)',
starting: '',
ending: '',
gasPriceCurrent: '',
visible: false
});
}
render() {
return (
<LinearGradient
colors = {['#051937', '#A8EB12']}
style ={styles.homeScreen}
locations = {[0.23, 1]}
start={{x: 0, y: 0}}
end={{x: 0, y: 1}}>
<Text style={styles.heading}>Hello</Text>
<Text style={styles.subHeading}>
Please start recording your starting and ending gas amounts
</Text>
<View style={styles.inputContainer}>
<TouchableOpacity onPress={this.showDateTimePicker}>
<SpecialText
content = {this.state.date}
style={{
fontSize: 22,
color: this.state.dateColor
}}
/>
</TouchableOpacity>
<DateTimePicker
isVisible={this.state.visible}
onConfirm={this.handleDateConfirm}
onCancel={this.hideDatePicker}
/>
<SpecialInput
placeholder = {"Starting"}
iconName = 'ios-car'
iconText= ' KM'
maxLength={3}
style={styles.inputStyle}
value={this.state.starting}
placeholderTextColor={'rgba(255,255,255, 0.6)'}
onChange = {this.handleStartChange}
/>
<SpecialInput
placeholder = {"Ending"}
iconName = 'ios-car'
iconText= ' KM'
maxLength={3}
style={styles.inputStyle}
value={this.state.ending}
placeholderTextColor={'rgba(255,255,255, 0.6)'}
onChange={this.handleEndChange}
/>
<SpecialInput
placeholder = {"Current Gas Prices"}
iconName = 'ios-pricetags'
iconText= ' cents'
maxLength={5}
style={styles.inputStyle}
value={this.state.gasPriceCurrent}
placeholderTextColor={'rgba(255,255,255, 0.6)'}
onChange={this.handleGasChange}
/>
{/* Record the entry into data storage */}
<GenericButton
style={styles.recordButton}
textColor={'#ffffff'}
placeholder = "RECORD"
onPress={this.recordEntry} />
{/* RESET BUTTON */}
<GenericButton
style={styles.clearButton}
textColor={'#ffffff'}
placeholder = "CLEAR"
onPress={this.resetInput} />
</View>
</LinearGradient>
);
}
}
function mapStateToProps(state) {
return {
records: state.records
}
}
// Here is where I noticed most of the errors pointing to
const mapDispatchToProps = dispatch => {
return {
addRecord: (record) => {
dispatch(addRecord(record))
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MainScreen)
'''
我的recordReducer.js
'''
// recordReducer.js
import { ADD_RECORD } from '../actions/types'
const initialState = {
records: ['Chicken Joe']
};
const recordReducer = (state = initialState, action) => {
switch(action.type) {
case ADD_RECORD:
return {
...state,
records: state.records.concat(action.value)
};
default:
return state;
}
}
export {recordReducer};
'''
actions / index.js '''
import ADD_RECORD from './types';
// Add Record Action
export const addRecord = record => {
return {
type: ADD_RECORD,
payload: record
}
}
'''
actions / types.js
'''
export const ADD_RECORD = 'ADD_RECORD';
'''
如前所述,我只想弄清楚如何将数据保存在存储中,以后再从任何组件/屏幕/视图中检索它们。
非常感谢任何尝试帮助我的人!我已经连续12个小时了:(
编辑1:
这是我遇到的新错误。唯一的变化是,在actions/index.js
中,我做了正确的named import
。
答案 0 :(得分:2)
您在actions.js
中有一个错字。您正在导入:
import ADD_RECORD from './types';
但是,这是默认导入,而types.js
正在执行命名为导出:
export const ADD_RECORD = 'ADD_RECORD';
您需要使用匹配的导入和导出语法,否则导入的值将为undefined
。这导致操作对象具有未定义的type
字段,从而导致Redux错误。
因此,将actions.js
更改为使用命名导入,就像在reducer文件中一样:
import {ADD_RECORD} from "./types";
此外,当您拥有atm代码时,可以简化mapDispatch
中的MainScreen.js
定义以使用the "object shorthand" form of mapDispatch
:
const mapDispatch = {addRecord};
作为旁注,我强烈建议您使用our new Redux Starter Kit package,它会自动为您生成动作类型和动作创建者函数,因此您无需手动编写它们。