【发布时间】:2017-11-05 12:07:06
【问题描述】:
我在我的 EmployeeEdit.js 文件中收到未定义名称属性的类型错误。当我触摸员工列表上的一项时,我收到此错误,而不是使用传递的参数进入员工编辑表单。我在控制台登录并发现 state.employeeForm 没有从 EmployeeFormReducer 加载值{ name, phone, shift }。我不确定为什么。
这是错误
TypeError: Cannot read property 'name' of undefined
This error is located at:
in Connect(EmployeeForm) (at EmployeeEdit.js:21)
in RCTView (at View.js:113)
in View (at Card.js:6)
in Card (at EmployeeEdit.js:20)
in EmployeeEdit (created by Connect(EmployeeEdit))
in Connect(EmployeeEdit) (at SceneView.js:35)
in SceneView (at CardStack.js:413)
in RCTView (at View.js:113)
in View (at createAnimatedComponent.js:134)
in AnimatedComponent (at Card.js:28)
in Card (at PointerEventsContainer.js:55)
in Container (at CardStack.js:443)
in RCTView (at View.js:113)
in View (at CardStack.js:373)
in RCTView (at View.js:113)
in View (at CardStack.js:372)
in CardStack (at CardStackTransitioner.js:110)
in RCTView (at View.js:113)
in View (at Transitioner.js:192)
in Transitioner (at CardStackTransitioner.js:60)
in CardStackTransitioner (at StackNavigator.js:48)
in Unknown (at createNavigator.js:36)
in Navigator (at createNavigationContainer.js:198)
in NavigationContainer (at App.js:37)
in Provider (at App.js:36)
in App (at renderApplication.js:35)
in RCTView (at View.js:113)
in View (at AppContainer.js:102)
in RCTView (at View.js:113)
in View (at AppContainer.js:126)
in AppContainer (at renderApplication.js:34)
EmployeeEdit.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import _ from 'lodash';
import EmployeeForm from './EmployeeForm';
import { employeeUpdate } from '../actions';
import { Card, CardSection, Button } from './common';
class EmployeeEdit extends Component {
componentWillMount() {
_.each(this.props.navigation.state.params.employee, (value, prop) => {
this.props.employeeUpdate({ prop, value });
});
}
onButtonPress() {
const { params } = this.props.navigation.state;
const { name, phone, shift } = params.employee;
}
render() {
return (
<Card>
<EmployeeForm {...this.props} />
<CardSection>
<Button onPress={() => this.onButtonPress.bind(this)}>
Save Changes
</Button>
</CardSection>
</Card>
);
}
}
const mapStateToProps = (state) => {
const { name, phone, shift } = state.employeeForm;
return { name, phone, shift };
};
export default connect(mapStateToProps, { employeeUpdate })(EmployeeEdit);
EmployeeList.js
import React, { Component } from 'react';
import { FlatList } from 'react-native';
import { connect } from 'react-redux';
//import { R } from 'ramda';
import _ from 'lodash';
import { employeesFetch } from '../actions';
import { HeaderButton } from './common';
import ListEmployee from './ListEmployee';
class EmployeeList extends Component {
static navigationOptions = ({ navigation }) => ({
headerRight: (
<HeaderButton onPress={() => navigation.navigate('employeeCreate')}>
Add
</HeaderButton>
)
});
componentWillMount() {
this.props.employeesFetch();
}
keyExtractor(item) {
return item.uid;
}
renderItem({ item }) {
return <ListEmployee employee={item} navigation={this.props.navigation} />;
}
render() {
return (
<FlatList
data={this.props.employees}
renderItem={this.renderItem.bind(this)} // Only for test
keyExtractor={this.keyExtractor}
navigation={this.props.navigation}
/>
);
}
}
const mapStateToProps = (state) => {
const employees = _.map(state.employees, (val, uid) => ({ ...val, uid }));
return { employees };
};
export default connect(mapStateToProps, { employeesFetch })(EmployeeList);
ListEmployee.js
import React, { Component } from 'react';
import {
Text,
StyleSheet,
TouchableWithoutFeedback,
View
} from 'react-native';
import { CardSection } from './common';
class ListEmployee extends Component {
render() {
const { employee } = this.props;
const { navigate } = this.props.navigation;
const { textStyle } = styles;
const { name } = this.props.employee;
return (
<TouchableWithoutFeedback onPress={() => navigate('employeeEdit', { employee })}>
<View>
<CardSection>
<Text style={textStyle}>{name}</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
/**
second argument in connect does 2 things. 1. dispatches all actions creators
return action objects to the store to be used by reducers; 2. creates props
of action creators to be used by components
**/
export default ListEmployee;
const styles = StyleSheet.create({
textStyle: {
fontSize: 18,
paddingLeft: 15,
}
});
EmployeeForm.js
import React, { Component } from 'react';
import { Picker, Text, StyleSheet, View } from 'react-native';
import { connect } from 'react-redux';
import { employeeUpdate } from '../actions';
import { CardSection, Input } from './common';
class EmployeeForm extends Component {
render() {
return (
<View>
<CardSection>
<Input
label="Name"
placeholder="Jane"
value={this.props.name}
onChangeText={value => this.props.employeeUpdate({ prop: 'name', value })}
/>
</CardSection>
<CardSection>
<Input
label="Phone"
placeholder="xxx-xxxx"
value={this.props.phone}
onChangeText={value => this.props.employeeUpdate({ prop: 'phone', value })}
/>
</CardSection>
<CardSection>
<Text style={styles.pickerTextStyle}>Shift</Text>
<Picker
style={{ flex: 1 }}
selectedValue={this.props.shift}
onValueChange={value => this.props.employeeUpdate({ prop: 'shift', value })}
>
<Picker.Item label="Monday" value="Monday" />
<Picker.Item label="Tuesday" value="Tuesday" />
<Picker.Item label="Wednesday" value="Wednesday" />
<Picker.Item label="Thursday" value="Thursday" />
<Picker.Item label="Friday" value="Friday" />
<Picker.Item label="Saturday" value="Saturday" />
<Picker.Item label="Sunday" value="Sunday" />
</Picker>
</CardSection>
</View>
);
}
}
const styles = StyleSheet.create({
pickerTextStyle: {
fontSize: 18,
paddingLeft: 20
}
});
const mapStateToProps = (state) => {
const { name, phone, shift } = state.EmployeeForm;
return { name, phone, shift };
};
export default connect(mapStateToProps, { employeeUpdate })(EmployeeForm);
这是我的 combineReducers
import { combineReducers } from 'redux';
import AuthReducer from './AuthReducer';
import EmployeeFormReducer from './EmployeeFormReducer';
import EmployeeReducer from './EmployeeReducer';
import SelectionReducer from './SelectionReducer';
export default combineReducers({
auth: AuthReducer,
employeeForm: EmployeeFormReducer,
employees: EmployeeReducer,
selectedEmployeeId: SelectionReducer
});
这里是 EmployeeFormReducer
import { EMPLOYEE_UPDATE, EMPLOYEE_CREATE } from '../actions/types';
const INITIAL_STATE = {
// prop: 'name', value: ''
name: '',
phone: '',
shift: ''
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case EMPLOYEE_UPDATE:
// [] is NOT an array; a syntax to convert value into key; called key interpolation??
return { ...state, [action.payload.prop]: action.payload.value };
case EMPLOYEE_CREATE:
return INITIAL_STATE;
default:
return state;
}
};
这是动作创建者
export const employeeUpdate = ({ prop, value }) => {
return {
type: EMPLOYEE_UPDATE,
payload: { prop, value }
};
};
这是 EmployeeForm.js
import React, { Component } from 'react';
import { Picker, Text, StyleSheet, View } from 'react-native';
import { connect } from 'react-redux';
import { employeeUpdate } from '../actions';
import { CardSection, Input } from './common';
class EmployeeForm extends Component {
render() {
return (
<View>
<CardSection>
<Input
label="Name"
placeholder="Jane"
value={this.props.name}
onChangeText={value => this.props.employeeUpdate({ prop: 'name', value })}
/>
</CardSection>
<CardSection>
<Input
label="Phone"
placeholder="xxx-xxxx"
value={this.props.phone}
onChangeText={value => this.props.employeeUpdate({ prop: 'phone', value })}
/>
</CardSection>
<CardSection>
<Text style={styles.pickerTextStyle}>Shift</Text>
<Picker
style={{ flex: 1 }}
selectedValue={this.props.shift}
onValueChange={value => this.props.employeeUpdate({ prop: 'shift', value })}
>
<Picker.Item label="Monday" value="Monday" />
<Picker.Item label="Tuesday" value="Tuesday" />
<Picker.Item label="Wednesday" value="Wednesday" />
<Picker.Item label="Thursday" value="Thursday" />
<Picker.Item label="Friday" value="Friday" />
<Picker.Item label="Saturday" value="Saturday" />
<Picker.Item label="Sunday" value="Sunday" />
</Picker>
</CardSection>
</View>
);
}
}
const styles = StyleSheet.create({
pickerTextStyle: {
fontSize: 18,
paddingLeft: 20
}
});
const mapStateToProps = (state) => {
const { name, phone, shift } = state.EmployeeForm;
return { name, phone, shift };
};
export default connect(mapStateToProps, { employeeUpdate })(EmployeeForm);
【问题讨论】:
-
我不使用来自 RN 的正常导航,但我不认为值是在导航内部的状态中传递的。你从哪里得到的?
-
它们实际上是作为道具传递的。我控制台登录以检查它们。我不认为这是问题
-
这样的话,看我的回答
-
我还没有实现按钮按下。基本上,逻辑是
{ employee}被传递给 EmployeeEdit 表单并通过 redux 进行更新。连接 react-redux 应该更新 state.employeeForm 但它不是出于某种原因。按下按钮将更新 firebase。如果我能解决这个问题
标签: react-native react-navigation react-native-flatlist