react-native redux 访问/操作一个对象

react-native redux accessing / manipulating an object

您好,我有这个对象,将对其进行一些 mathematical/statistical 操作。现在我有问题了:

  1. 如何访问它?例如,我想访问 numbers[0]['B1'] 当我执行 {this.props.numbers[0]['B1']} 时,我得到: Cannot read 属性 B1 of undefined.

  2. 如果我想对这些数字做一些计算,我应该把它们放在哪里?根据我对 react redux 的有限经验,我知道我不应该在 reducer 中做那样的事情,对吗?我会创建更多动作(动作创建者)吗?获取平均 B1 数,或对数字进行任何统计操作等。是否建议将 'reselect' 用于此类任务?

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
  },
....

家庭容器

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'。此外,控制台不会记录 'not yet loaded',这表明数字对象在那里 - 我只是在访问它时出错。

编辑 2:

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:63Cannot read 属性 'B1' 个未定义。

How do I access it? For Example I'd like to access numbers[0]['B1'] When I do {this.props.numbers[0]['B1']} I get: Cannot read property B1 of undefined.

看起来你所有的 react/redux 接线都很好,只是 getDatacomponentDidMount 中被调用所以对于第一次渲染,数据还没有(请参阅 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>
    );
  }

If I want to do some calculations on those numbers, where would I put them? From my limited experience with react redux, I know I should not do anything like that in reducers, am I right? Would I create more actions (action creators) to eg. get the average B1 number, or any statistical operations on the numbers, etc. Would it be recommended to use 'reselect' for this kind of tasks?

这将取决于计算的密集程度。如果它们很便宜,我就在渲染函数中做它们

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 不是未定义的(它由减速器的初始状态定义)。如果您检查长度,它将呈现(我已经复制了所有这些代码并且 运行 自己来确定这次)。

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 语句中实际 return 某些东西(或 null)很重要,这样它就不会达到 undefined 值(this.props.numbers[0])。


说明(在评论中要求)

这一切都归结为 component's lifecycle

当组件挂载时它有一个空数组,由reducer

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

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

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

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

所以组件不会 "keep re-rendering until the numbers object is not empty",只要 props 改变,它就会重新渲染,如果数字数组不为空,将包含所需的组件。

返回 nullvalid in react,通常用于防止组件尝试访问尚不可用的道具。