【问题标题】:type error undefined name property in react native components反应本机组件中的类型错误未定义名称属性
【发布时间】: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


【解决方案1】:

我认为你的问题是你没有约束力。试试这个:

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

【讨论】:

  • 我已经调用了 .bind(this) 所以我相信我不应该在这里使用胖箭头。这两种方式都无关紧要。
【解决方案2】:

问题是 EmployeeForm.js;这是 EmployeeEdit.js 和 EmployeeForm.js 之间共享的通用组件。它从 2 个中的任何一个接收,但它不能有 mapStateToProps,因为它最终会覆盖负责管理 redux 状态的其父级的 mapStateToProps。所以我摆脱了它,并且 combinereducers 能够正确地将 state.key 与其相应的值匹配,即在其函数调用中声明的 reducers。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 2019-12-22
    • 2020-05-25
    • 1970-01-01
    • 2020-10-28
    • 2019-11-16
    • 1970-01-01
    相关资源
    最近更新 更多