2017-11-05 13 views
0

未定義のnameプロパティの型エラーが発生しました。私はEmployeeEdit.jsファイルを信じています。従業員リストの1つの項目をタッチすると、渡されたパラメータで従業員編集フォームに行くのではなく、このエラーが発生します。私はコンソールにログインし、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); 

ここでは、ここでアクションの作成者が「

ここ
export const employeeUpdate = ({ prop, value }) => { 
    return { 
    type: EMPLOYEE_UPDATE, 
    payload: { prop, value } 
    }; 
}; 

だここ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; 
    } 
}; 

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 
    }); 

私combineReducersですs 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); 
+0

RNからの通常のナビゲーションは使用しませんが、ナビゲーション内の状態で値が渡されるとは思われません。どこでそれを手に入れたのですか? – sfratini

+0

彼らは実際に小道具として渡されます。私はそれらを確認するためにログオンコンソールです。私はそれが問題だとは思わない –

+0

その場合は、私の答えを参照 – sfratini

答えて

1

私はあなたの問題はあなたが束縛していないと思っています。試してみてください:

onButtonPress =() => { 
    const { params } = this.props.navigation.state; 
    const { name, phone, shift } = params.employee; 
    } 
+0

私はすでに.bind(this)と呼んでいますので、ここで太い矢印を使う必要はありません。これはいずれの方法とも関係ありません。 –

0

問題はEmployeeForm.jsでした。これはEmployeeEdit.jsとEmployeeForm.jsの間で共有される一般的なコンポーネントです。それは2のいずれかから受け取りますが、それは、還元状態を管理する責任がある親のmapStateToPropsをオーバーライドするので、mapStateToPropsを持たなくてはなりません。だから、私はそれを取り除き、combinereducersはstate.keyをその対応する値、つまり関数呼び出しで宣言された減速子に適切にマッチさせることができました。

関連する問題