react-native redux访问/操作对象

时间:2017-03-26 10:15:40

标签: json react-native react-redux

您好我有这个对象,并且会对它做一些数学/统计操作。现在我有问题:

  1. 如何访问它?例如,我想访问数字[0] ['B1'] 当我做{this.props.numbers [0] ['B1']}时,我得到:无法读取未定义的属性B1。

  2. 如果我想对这些数字进行一些计算,我会把它们放在哪里?根据我对react redux的有限经验,我知道我不应该在减速器中做任何类似的事情,对吗?我会为例如创建更多动作(动作创建者)吗?获得平均B1数,或对数字进行任何统计操作等。是否建议使用“重新选择”来完成此类任务?

  3. The Object called numbers

    numReducer

    import { LIST_NUMBERS, PICK_NUMBER, GET_DATA } from '../actions/actionTypes';
    
    export default (state = [], action = {}) => {
      switch (action.type) {
        case LIST_NUMBERS:
          return action.payload || [];
        case PICK_NUMBER:
          return action.payload;
        case GET_DATA:
          return action.payload;
        default:
          return state;
      }
    };
    

    动作:

    import { LIST_NUMBERS, PICK_NUMBER, GET_DATA } from './actionTypes';
    import dataSet from '../data.json';
    
    export const listNumbers = () => {
      const nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
      return {
        type: LIST_NUMBERS,
        payload: nums
      };
    };
    
    export const getData = () => {
      return {
        type: GET_DATA,
        payload: dataSet
      };
    };
    
    export const pickNumber = (num) => {
      return {
        type: PICK_NUMBER,
        payload: num
      };
    };
    

    data.json

    [
      {
        "DrawDate": "22-Mar-17",
        "B1": 12,
        "B2": 6,
        "B3": 11,
        "B4": 31,
        "B5": 27,
        "B6": 19,
        "BB": 42,
        "BS": 1,
        "DrawNumber": 2217
      },
      {
        "DrawDate": "18-Mar-17",
        "B1": 26,
        "B2": 37,
        "B3": 8,
        "B4": 3,
        "B5": 19,
        "B6": 41,
        "BB": 43,
        "BS": 3,
        "DrawNumber": 2216
      },
    ....
    

    Home Container

    import { bindActionCreators } from 'redux';
    import { connect } from 'react-redux';
    
    import { listNumbers, pickNumber, getData } from '../actions/numberActions';
    
    import Home from '../components/Home';
    
    const mapStateToProps = state => ({
      numbers: state.numbers
    });
    
    const mapDispatchToProps = dispatch => (
      bindActionCreators({
        listNumbers,
        pickNumber,
        getData
      }, dispatch)
    );
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(Home);
    

    主页组件:

    import React, { Component } from 'react';
    import { View, Text, Button, TextInput } from 'react-native';
    
    export default class Home extends Component {
      static navigationOptions = {
        title: 'Home Screen',
      };
      componentDidMount() {
        this.props.getData();
      }
    
      render() {
        const { navigate } = this.props.navigation;
        return (
          <View>
            <Text>####################</Text>
            <Text>Intro Screen</Text>
            <Text>Number: {this.props.numbers[0]['B1']}</Text>
          </View>
        );
      }
    
    }
    

    EDIT / ADDITION:

    根据以下建议,我已将生命周期方法更改为ComponentWillMount,并添加了一个检查以查看是否已加载this.props.numbers。

    import React, { Component } from 'react';
    import { View, Text, Button, TextInput } from 'react-native';
    
    export default class Home extends Component {
      static navigationOptions = {
        title: 'Home Screen',
      };
    
      componentWillMount() {
        this.props.getData();
      }
    
      render() {
        if (!this.props.numbers) {
           console.log('not yet loaded'); // or a spinner?
         }
        const { navigate } = this.props.navigation;
        return (
          <View>
            <Text>####################</Text>
            <Text>Intro Screen</Text>
            <Text>Number: {this.props.numbers[0]['B1']}</Text>
    
          </View>
        );
      }
    
    }
    

    我仍然得到同样的错误:无法读取未定义的属性'B1'。此外,控制台不会记录“尚未加载”,这表示数字对象存在 - 我只是在访问它时出错。

    EDIT2:

    import React, { Component } from 'react';
    import { View, Text, Button, TextInput } from 'react-native';
    
    export default class Home extends Component {
      static navigationOptions = {
        title: 'Home Screen',
      };
    
      componentWillMount() {
        this.props.getData();
      }
    
      listNums() {
        return this.props.numbers.map((num) => num['B1']);
      }
      listSingleNum() {
        return this.props.numbers[0]['B1'];
      }
      render() {
        if (!this.props.numbers) {
           console.log('not yet loaded'); // or a spinner?
         } else {
           console.log(this.listNums());
         }
        const { navigate } = this.props.navigation;
        return (
          <View>
            <Text>####################</Text>
            <Text>Intro Screen</Text>
            <Text>Number: {this.listNums()}</Text>
    
          </View>
        );
      }
    
    }
    

    因此listNums()可以正常显示每个元素的B1,但是如果我尝试访问listSingleNum中的单个B1元素,则会抛出前面提到的错误:ExceptionsManager.js:63无法读取未定义的属性“B1”。

1 个答案:

答案 0 :(得分:2)

  

我如何访问它?例如,我想访问数字[0] ['B1']当我这样做{this.props.numbers [0] ['B1']}时,我得到:无法读取未定义的属性B1。

看起来你的所有react / redux接线都很好,只是在getData中调用了componentDidMount,所以对于第一次渲染,数据还不存在(参见文档) lifecycle methods order)。您可以使用componentWillMount代替,但我仍然不确定数据是否可用于第一次渲染。为了安全起见,如果numbersundefined,请更改渲染函数以执行不同的操作(如果最终从某个后端加载数据,则必须执行此操作)。

注意:以下内容不正确 - 请参阅下面的编辑

render() {
    if (!this.props.numbers) {
      return null; // or a spinner?
    }

    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>####################</Text>
        <Text>Intro Screen</Text>
        <Text>Number: {this.props.numbers[0]['B1']}</Text>
      </View>
    );
  }
  

如果我想对这些数字进行一些计算,我会把它们放在哪里?根据我对react redux的有限经验,我知道我不应该在减速器中做任何类似的事情,对吗?我会为例如创建更多动作(动作创建者)吗?得到平均B1数,或对数字的任何统计操作等。是否建议使用“重新选择”来完成这类任务?

这取决于计算的密集程度。如果它非常便宜,我只需在渲染功能中执行它们

import calculateAverage from './somewhere'

...

return (
  <View>
    <Text>####################</Text>
    <Text>Intro Screen</Text>
    <Text>Number: {this.props.numbers[0]['B1']}</Text>
    <Text>Average: {calculateAverage(this.props.numbers.map((data) => data['B1'])}</Text>
  </View>
);

如果计算成本很高,则重新选择是一个不错的选择,这样它就不会在每次渲染时不必要地重新计算值。它比测试组件本身的逻辑更好。

编辑:哇......此刻我感觉有点傻了......

this.props.numbers未定义(由reducer的初始状态定义)。如果检查长度,它将呈现(我已经复制了所有这些代码并自己运行以确保这一次)。

render() {
    if (this.props.numbers.length === 0) {
      return null; // or a spinner?
    }

    const { navigate } = this.props.navigation;
    return (
      <View>
        <Text>####################</Text>
        <Text>Intro Screen</Text>
        <Text>Number: {this.props.numbers[0]['B1']}</Text>
      </View>
    );
  }

在if语句中实际返回一些内容(或null)非常重要,这样它就不会达到undefined值(this.props.numbers[0])。

解释(在评论中提出要求)

这一切归结为component's lifecycle

当组件安装时,它有一个空数组,由reducer的initialState设置

export default (state = [], action = {}) => {
  ...
};

mounting lifecycle methods将按顺序触发。当componentDidMount(或componentWillMount取决于我们所处的问题的更新时)状态将在redux存储中被替换为具有完整数据集。

安装生命周期完成后,react-redux将更改触发道具更改,触发updating lifecycle methods

在此阶段,再次调用渲染,这次使用正确的数据。

因此组件不会“继续重新渲染,直到数字对象不为空”,只要道具发生变化,它就会重新渲染,如果数组数组不为空,则会包含所需的组件。

返回nullvalid in react,通常用于阻止组件尝试访问尚未提供的道具。