状态未使用动态复选框更新

时间:2018-08-12 08:36:09

标签: react-native redux react-redux

更新:我最终只是从部分列表切换到滚动视图,并且状态正确更新。我不了解Pure Component,这就是它没有重新渲染的原因。

我对原生反应非常陌生,我正在使用redux之类解决很多问题。但是,我似乎无法理解为什么状态更改时我的组件没有更新。我不确定需要多少信息,所以我将尝试在应关注的代码中添加注释。

复选框是通过api调用动态呈现的。然后,我使用该数据创建一个具有true / false值的项目列表,以将其传递给复选框。列表中的键专门与每个复选框相关联。我试图将其保持尽可能的动态,以允许后端的数据更改。当按下复选框时,CHECK调度将触发并按预期更新状态,但是不会更新该复选框以反映该状态。打印清单的状态表明状态正在正确更新。 Redux可以正常工作,但是复选框的选中状态没有改变。

最大的问题是:为什么该复选框未使用新状态更新?
先谢谢了。

我的代码如下:

Details.js(容器)

import React, { Component } from 'react'
import { connect } from 'react-redux'
import { actionCreators } from '../redux/actionCreators'
import DetailsScreen from '../components/DetailsScreen';  

class Details extends Component {
  componentDidMount() {
    const { getRouteList } = this.props
    getRouteList()
  }

  render() {
    const { listReady, routeList, checkedList, check } = this.props
    return (
      <DetailsScreen
        sections={routeList}
        listReady={listReady}
        checkedList={checkedList} //passing list of items with true/false values to DetailsScreen
        check={check} //function that calls an actionCreators(dispatch) below **this works**
      />
    )
  }    
}

const mapStateToProps = (state) => ({
  listReady: state.listReady,
  routeList: state.routeList,
  checkedList: state.checkedList //list of items that correlate with the checked state of the checkboxes, e.g. state.checkedList[0] = Item1: true
})

const mapDispatchToProps = (dispatch) => ({
  getRouteList: () => {
    dispatch(actionCreators.getRouteList())
  },
  check: key => {
    dispatch(actionCreators.check(key))
  }
})

export default connect(mapStateToProps, mapDispatchToProps)(Details)

DetailsS​​creen.js(组件)

import React, { Component } from 'react'
import { View, Text, SectionList, StyleSheet } from 'react-native'
import { Button, CheckBox } from 'react-native-elements'
import { connect } from 'react-redux'
import { actionCreators } from '../redux/actionCreators'

const extractKey = ({ id }) => id

class DetailsScreen extends Component {
  renderItem = ({ item }) => {
    const {checkedList, check} = this.props
    return (
      <CheckBox
        title={item.Description}
        checked={checkedList[item.Description]} //getting the state of the checkbox from checkedList **this works, initially shows up correctly, but does not get updated**
        checkedIcon='plus-square'
        checkedColor='blue'
        uncheckedIcon='minus-circle'
        uncheckedColor='red'
        onPress={() => check(item.Description)} //action creator helper that switches the state of the item (true/false)
      />
    )
  }

  renderSectionHeader = ({ section }) => {
    return (
      <Text style={styles.header}>
        {section.title}
      </Text>
    )
  }

  render() {
    const { sections, listReady } = this.props
    if (listReady) {
      return (
        <SectionList
          style={styles.container}
          sections={sections}
          renderItem={this.renderItem}
          renderSectionHeader={this.renderSectionHeader}
          keyExtractor={extractKey}
        />
      )
    }
    return (
      <View>
        <Text>Loading...</Text>
      </View>
    )
  }
}

const styles = *styles for stuff above*

export default DetailsScreen

actionCreators.js

import * as types from './actionTypes'
import { AsyncStorage } from "react-native"

export const actionCreators = {
  check: key => {
    return {
      type: types.CHECK,
      payload: key //item.Description from the checkbox
    }
  },
  getRouteList: () => {
    return {
      type: types.GET_ROUTE_LIST,
      payload:
        fetch(url)
          .then(result => result.json()) //result is formed for a React Native SectionList
          .catch(() => [])
    }
  }
*other actions*
}

reducer.js

import * as types from './actionTypes'

export const initialState = {
  routeList: [],
  checkedList: {},
  listReady: false,
}

export const reducer = (state = initialState, action) => {
  const { type, payload } = action

  switch (type) {
    case types.CHECK:
      console.log(state.checkedList) //shows that the state IS indeed being updated, but it is not changing on the checkbox
      return {
        ...state,
        checkedList: {...state.checkedList, [payload]: !state.checkedList[payload]} 
      }

    case types.GET_ROUTE_LIST_FULFILLED:
      list = {}
      payload[0].data.map((item) => { //
        if (item.Description == "Route 1") { //test to make sure that that the checkboxes were initially getting set correctly
          list[item.Description] = true
        }
        else list[item.Description] = false
      })
      return {
        ...state,
        routeList: payload, //checkboxes are rendered with this 
        listReady: true,
        checkedList: list //this holds the state of the checkedness of the checkboxes **updated in CHECK reducer**
      }

    default:
      return state
  }
}

1 个答案:

答案 0 :(得分:0)

我不是本地反应专家,但问题与“正常反应”有关。

未成年人:key中有一个<CheckBox >属性-在index中使用renderItem参数

更成问题的是数据结构/参数传递。 SectionListpureComponent-由于性能原因,使用浅等于-在数据不变时不会重新呈现。但是,即使它是正常的组件也无法使用;)-SectionList会获得不变的道具-sectionssections={routeList})。

routeList未更新,则不重新渲染SectionListSectionList不知道项目(<CheckBox >)使用checkedList

如何解决?

  1. 您可以将checkedListsections(标记选中的部分/项目)组合(在渲染中)以创建作为“部分”传递的新sectionsChecked数组。每次对render的调用都会创建一个新数组,强制刷新SectionList
  2. 如上所述,但使用mapStateToPorps
  3. 一切照旧,但让SectionList感觉到它获取了新数据-传递新的引用是绝对的。使用任何您喜欢的方法传递sections的副本,这会导致新的对象/数组。

第3种方法可能不够好,因为renderItem应该提供数据作为道具(在每个部分中都进行了“检查”)-pureComponent刷新问题-它不应是深层对象属性/派生数据。

所有内容都在文档中进行了描述。