【问题标题】:React Native + Redux: How to render <ListView/> upon clicking a button?React Native + Redux:如何在单击按钮时呈现 <ListView/>?
【发布时间】:2016-09-24 09:17:25
【问题描述】:

我有两个组件:AddingAnimalPanel.jsAnimalList.js。我试图做以下事情:

AddingAnimalPanel.js 中,我有一个按钮,一旦单击它,它就会调用函数_addAnimal() 并通过redux 更新状态,更新后的状态被传递到AnimalList.js 并通过@ 列出状态987654326@。

但我收到一个错误:Cannot read property 'rowIdentities' of undefined,我没有为animalData 定义初始状态。所以我尝试将初始状态属性animalData 定义为一个数组,但仍然出现错误:Cannot read property 'length' of undefined

我似乎无法弄清楚出了什么问题。我做错了什么?

这是我的代码:

AddingAnimalPanel.js:

  _addAnimal() {
    var animals = [{animal: 'bird'}, {animal: 'cat'}, {animal: 'dog'}]

    var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    var animalData = ds.cloneWithRows(animals)

    this.props.uploadAnimalData(animalData) //Calling action creator
  }

在行动创作者:

export const uploadAnimalData = (animalData) => {
  return {
    type: actionTypes.UPLOAD_ANIMAL_DATA,
    animalData: animalData,
  }
}

在减速机中:

const DEFAULT_STATE = {
 //Tried also both animalData:[] and animalData:{} but still got the length error
}

export default function(state = DEFAULT_STATE, action) {
  switch(action.type) {

    case actionTypes.UPLOAD_ANIMAL_DATA:
      return {
        ...state,
        animalData: action.animalData
      }
    default:
      return state
  }
}

redux 工作正常,props 被传递给AnimalList.js

  _renderRow(rowData){
    return (
      <AnimalListRow rowData={rowData} {...this.props}/>
    )
  }

  render() {

    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.props.animalData} //ListView is causing the error
          renderRow={this._renderRow}
        />
      </View>
    )
  }
}

编辑 - 附加代码

这是我目前为 redux 设置的。

减速机:

const DEFAULT_STATE = {

}

export default function(state = DEFAULT_STATE, action) {
  switch(action.type) {

    case actionTypes.UPLOAD_ANIMAL_DATA:
      return {
        ...state,
        animalData: action.animalData
      }
    default:
      return state
  }
}

export const getAnimalData = (state) => ({
  animalData: state.animalData,
})

在名为 index.js 的单独文件中使用 react-redux 中的 connect,这就是 animalData 被传递到 AnimalList.js 的方式:

// @flow
import AnimalList from './AnimalList'
import { connect } from 'react-redux'
import * as actions from './actions'
import {
  getAnimalData,
} from '../../reducers/rootReducer'

const mapStateToProps = (state) => ({
  ...getAnimalData(state),
})

export default connect(mapStateToProps, actions)(AnimalList)

【问题讨论】:

  • 我对反应很陌生,redux。但是当我想从我的组件中调度一个动作创建者时,我将我的组件与 mapDispatchToProps 函数连接到 redux 状态。function mapStateToProps(state, ownProps) { return { animalData: animalData }; } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(uploadAnimalData, dispatch) }; } export default connect(mapStateToProps, mapDispatchToProps)(AddingAnimalPanel);
  • @BadChanneler 感谢您的回复,但您介意将其作为答案吗?很难弄清楚你的建议。
  • 调试时你检查过 props 变量吗?似乎您没有通过 getAnimalData 方法在 redux 中传递 animalData 道具。同样在 reducer 中,我会使用 Object.assign({}, state... 来合并 state 和 animalData 属性。

标签: javascript listview reactjs react-native redux


【解决方案1】:

我认为你在正确的轨道上,这很可能是初始数据的问题。但是,如果没有可执行的示例,很难确定确切的问题。

ListView 提供任何对象或数组都不起作用。您必须将ds.cloneWithRows()ds.cloneWithRowsAndSections() 的结果提供给ListView 组件。

可以采取多种措施。我建议将Listview.DataSource-功能移动到更靠近它的使用位置,即AnimalList 组件。你最初存储在 Redux 存储中的内容可能是一个空数组。使用来自react-reduxconnectAnimalList.js 的要点可能是:

import { connect } from 'react-redux';


    ...


    render() {
      return (
        <View style={styles.container}>
          <ListView
            dataSource={this.props.animalData} //ListView isn't causing an error
            renderRow={this._renderRow}
          />
        </View>
      );
   }
}

const ds = new ListView.DataSource({
  rowHasChanged: (r1, r2) => r1 !== r2
});

const mapStateToProps = (state) => {
  return {
    animalData: ds.cloneWithRows(state.animalReducer.animalData)
  };
};

export default connect(mapStateToProps)(AnimalList);

实现相同结果的另一种方法是延迟ListView 组件的渲染并推迟DataSource 创建直到animalData 可用。例如AnimalList.js:

  static propTypes = {
    animalData: React.PropTypes.array.isRequired
  };      

  ...

  render() {
    let animalListView = this.props.animalData.length >= 1
      <ListView
        dataSource={this.state.ds.cloneWithRows(this.props.animalData)}
        renderRow={this._renderRow}
      /> :
      null;

    return (
      <View style={styles.container}>
        {animalListView}
      </View>
    );
  }
}

编辑:我注意到您的代码还有几个潜在问题。

要将状态更改传播到 reducer,您需要从 Redux 调用 dispatch。你可能想在AddingAnimalPanel.js做的事情:

_addAnimal() {
  const { store } = this.context; // Assuming you're passing down a reference to store in context
  var animals = [{animal: 'bird'}, {animal: 'cat'}, {animal: 'dog'}]

  store.dispatch(this.props.uploadAnimalData(animals))
}

检查 reducer 中的 case actionTypes.UPLOAD_ANIMAL_DATA 是否因此被触发。

使用您发布的附加代码,如果我设法正确地想象您的代码在行动中,AnimalList.js

  render() {
    return (
      <View style={styles.container}>
        <ListView
          dataSource={this.props.animalData} //ListView isn't causing an error
          renderRow={this._renderRow}
        />
      </View>
    );
  }
}

const ds = new ListView.DataSource({
  rowHasChanged: (r1, r2) => r1 !== r2
});

const mapStateToProps = (state) => ({
  animalData: ds.cloneWithRows(...getAnimalData(state)),
})

export default connect(mapStateToProps, actions)(AnimalList)

然后我会做的,是设置

const DEFAULT_STATE = {
  animalData: []
}

在你的减速器中。这样state.animalData 始终是一个常规数组,AnimalList 组件将数据转换为ListView 期望接收数据的格式。

如果设置仍然不清楚,请尝试寻找示例应用程序,例如GitHub 并浏览该代码以了解它们是如何连接在一起的。

【讨论】:

  • 感谢您的回复。我用附加代码更新了原始代码以进一步澄清。我似乎无法理解它如何与我当前的 redux 设置一起工作。在我接受答案并投票之前,您能否用我的附加代码显示第一个建议?您还推荐第一个建议而不是第二个建议吗?努力学习最佳实践。谢谢 NiFi
【解决方案2】:

尝试以下方法并告诉我。首先,像以前一样在 reducer 中恢复初始状态:

const DEFAULT_STATE = {
 animalData:[] 
}

然后,在 reducer 中尝试以下操作:

case actionTypes.UPLOAD_ANIMAL_DATA:
  return Object.assign({}, state, {
    animalData: action.animalData,
  })

最后,在mapStateToProps 中使用state.animalData 访问列表。最后一部分可能不需要,我只是不确定您的getAnimalData 是如何使用的。

希望对你有帮助。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2018-03-28
  • 2018-05-29
  • 2019-06-17
  • 1970-01-01
  • 2018-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多