React-Native - 来自JSON for Switch的动态

时间:2016-06-23 11:11:04

标签: json filter react-native state

嘿那里:)我通过向我的SearchView添加过滤器Modal来获得以下问题

  

我构建了一个SearchPage,可以列出几个事件。这一切都很好。现在我正在尝试将filter添加到我的SearchPage。如果我手动设置过滤器,它可以很好地工作 - >现在我的问题:

     

如果我尝试更改Switch的切换值,则会将其设置回root,因为未设置该值的状态

我解释过的步骤:

  

我正在尝试打开一个Modal视图,其中列出了我的所有filter以及我可以使用true/false设置Switch的位置。我的想法是通过为其创建filter Settings来获取所有JSON

module.exports = {
  "filter":
      {
          "track": [
              {
                  "id": 1,
                  "description": "IoT & Living tomorrow"
              },
              {
                  "id": 2,
                  "description": "Smart & Digital Retail"
              },
              {
                  "id": 3,
                  "description": "Startups, Digital Culture & Collaboration"
              }
          ]
        }
  }

上面的JSON仅用于示例 - 通常它更大,并且有更多的主题而不仅仅是跟踪

  

现在我导入JSON并将其保存在var filter。我在这里检查了数据格式是否合适 - > filter.track -> All my JSON Objects

     

现在我用filter Modal

创建了一个班级

import React, {Component} from 'react';
import {
    ListView,
    Modal,
    StatusBar,
    StyleSheet,
    Text,
    TouchableOpacity,
    View,
    Switch
} from 'react-native';

var filter = require('../JSON/filter');

class PopoverFilter extends Component {

    constructor(props) {
        super();
        // ds for the menu entries
        var ds = new ListView.DataSource({rowHasChanged:   (r1, r2) => r1 !== r2});
        this.state = {
            eventTracks: ds.cloneWithRows(filter.filter.track)
        }
        this.show = this.show.bind(this);
    }

    render() {
        return(
            <Modal>
                         <ListView
                                style={styles.mainView}
                                renderRow={this.renderMenuEntries.bind(this)}
                                dataSource={this.state.eventTracks}/>
                        
            </Modal>
        );
    }

    renderMenuEntries(entry) {
        var switchState = entry.description;
        return(
            <View style={styles.switchView}>
                <Text style={[styleHelper.fonts.titleSize, styles.text]}>{entry.description}</Text>
                <Switch onValueChange={(value) => this.switchChanged(switchState, value)}
                value={this.state.switchState}/>
            </View>
        );
    }


    switchChanged(field, value) {
        var obj = {};
        obj[field] = value;
        this.setState(obj);
    }
}

var styles = StyleSheet.create({
    
});

module.exports = PopoverFilter;

  

请忽略缺少的样式,并且模态中还有更多的对象,但对于这种情况并不重要。

     

最重要的是我尝试使用renderMenuEntries方法渲染每个Switch,并为其提供所有条目 - &gt;只是Switch的工作没有正确设置。至于我试图改变开关的值,它立即回到它的根。并没有确定任何状态。

也许我的解决方案是不可能的,我必须使每个状态都是静态的 - 但是如果我可以在以后设置动态过滤器而不更改整个代码

,这个解决方案会非常好

2 个答案:

答案 0 :(得分:1)

您描述的场景是可能的。我的代码遇到了很多问题:

  1. renderMenuEntries中,您分配给<Switch />组件的值是数据项的 description ,而不是{{1}的预期布尔值组件<Switch />期望。此外,此值还引用了value不存在的属性。

  2. this.state功能也只是使用数据项 description

  3. 更新组件状态

    使用您提供的代码示例,我从头创建了一个名为switchChanged的新类。它不需要在此组件中使用过滤器数据,而是希望数据通过名为PopoverFilter的组件道具进入。这将促进组件的可重用性,以接受不同的数据集。

    对代码进行了大量评论,以帮助解释所演示的概念。这是filterData类:

    PopoverFilter

    请注意,此import React from 'react'; import { ListView, Modal, Switch, Text, TouchableOpacity, View } from 'react-native'; export default class PopoverFilter extends React.Component { constructor (props) { super(props); // bind relevant handlers up front in the constructor this.renderRow = this.renderRow.bind(this); this.onPress = this.onPress.bind(this); // process the incoming filter data to add a 'selected' property // used to manage the selected state of its companion switch this._filterData = this.processFilterData(this.props.filterData); const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }); this.state = { filterDataSource: ds.cloneWithRows(this._filterData) } } processFilterData (filterData) { // don't mutate the filterData prop coming in // use map to create a new array and use Object.assign to make // new object instances with a new property named 'selected' initialized // with a value of false return filterData.map((item) => Object.assign({}, item, { selected: false })); } switchChanged (rowId, isSelected) { const index = +rowId; // rowId comes in as a string so coerce to a number const data = this._filterData; // don't mutate this._filterData // instead create a new array and new object instance this._filterData = [ ...data.slice(0, index), // take everything before the target index Object.assign({}, data[index], { selected: isSelected }), // create a new object instance with updated selected property ...data.slice(index + 1) // take everything after the selected index ]; // update the listview datasource with the new data this.setState({ filterDataSource: this.state.filterDataSource.cloneWithRows(this._filterData) }); } renderRow (item, sectionId, rowId) { return( <View> <Text>{item.description}</Text> <Switch onValueChange={(value) => this.switchChanged(rowId, value)} value={item.selected} /> </View> ); } // just a test function used to dump the current state of the _filterData // to the console onPress () { console.log('data', this._filterData); } render () { return ( <Modal> <ListView renderRow={this.renderRow} dataSource={this.state.filterDataSource} /> <TouchableOpacity onPress={this.onPress}> <Text>Get Filter Data</Text> </TouchableOpacity> </Modal> ); } } 类还会显示一个按钮,按下该按钮会将当前数据状态转储到控制台,以便您可以查看它的当前表单。

    以下是如何使用该组件的示例:

    PopoverFilter

答案 1 :(得分:-1)

尝试

renderMenuEntries(entry) {
    var switchState = entry.description;
    return(
        <View style={styles.switchView}>
            <Text style={[styleHelper.fonts.titleSize, styles.text]}>{entry.description}</Text>
            <Switch onValueChange={(value) => this.switchChanged(switchState, value)}
            value={this.state[switchState]}/>
        </View>
    );
}


switchChanged(field, value) {
    var obj = this.state;
    obj[field] = value;
    this.setState({obj});
}