【问题标题】:State not updating with dynamic checkboxes状态未使用动态复选框更新
【发布时间】:2018-08-12 08:36:08
【问题描述】:

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

我对原生反应还很陌生,我正在用 redux 之类的东西搞清楚很多事情。但是,我似乎无法理解为什么我的组件在状态更改时没有更新。我不确定需要多少信息,所以我会尝试将 cmets 放入应该关注的代码中。

复选框是通过 api 调用动态呈现的。然后,我使用该数据创建具有真/假值的项目列表以传递给复选框。列表中的键专门与每个复选框相关联。我试图尽可能保持动态,以允许后端数据的更改。当复选框被按下时,CHECK 调度会触发并按预期更新状态,但不会更新复选框以反映该状态。打印checkedList 的状态表明状态正在正确更新。 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
  }
}

【问题讨论】:

    标签: react-native redux react-redux


    【解决方案1】:

    我不是 react-native 专家,但问题与“正常反应”有关。

    次要问题:&lt;CheckBox &gt; 中应该有一个 key 属性 - 在 renderItem 中使用 index 参数

    更成问题的是数据结构/参数传递。 SectionListpureComponent - 出于性能原因使用浅相等 - 当数据不更改时不会重新呈现。但即使它是普通组件,它也无法工作 ;) - SectionList 获得不会改变的道具 - sections (sections={routeList})。

    routeList 未更新,SectionList 未重新渲染。 SectionList 不知道该项目 (&lt;CheckBox &gt;) 使用 checkedList

    如何解决?

    1. 您可以将(在渲染中)checkedListsections(标记选中的部分/项目)结合起来创建新的sectionsChecked 数组作为“部分”传递。每次调用 render 都会创建新的数组,强制 SectionList 刷新。
    2. 同上,但使用mapStateToPorps
    3. 保持原样,但让SectionList 感觉它获得了新数据——传递新的引用就足够了。使用您喜欢的任何方法传递sections 的副本,从而生成新的对象/数组。

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

    这一切都在文档中描述。

    【讨论】:

    • 您能详细说明这里的第三个选项吗?您是否建议使用除部分列表之外的其他内容,以允许独立于列表更新复选框?滚动视图或类似的东西?
    • 第三个选项不是最佳选项... SectionList 可能已经过优化,并且可以很好地处理良好的数据(选项 1,2)... 但是您可以尝试使用“添加图层”renderItem (在 中嵌入 Checkbox)和 shouldComponentUpdate 以优化渲染(渲染
    • 你认为你可以举个例子吗?我不确定你是什么意思?我会接受答案。
    • sth like: &lt;SectionList sections={sections.slice()} - 但这是丑陋的把戏,你应该修复数据结构 (1,2) 而不是寻找解决方法
    猜你喜欢
    • 2016-11-25
    • 1970-01-01
    • 2020-02-28
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 2015-07-25
    • 2016-03-21
    • 1970-01-01
    相关资源
    最近更新 更多