3

Вот мой пример кода, мне бы хотелось, чтобы элементы ListView обновлялись по клику.React Native ListView не перерисовывается при изменении состояния нажатием

Эта строка определяет стиль:

(this.state.selectedField.id==field.id)?'green':'white' 

В этом примере активный View должен быть выделен зеленым цветом. Состояние обновляется внутри handleClick(), но метод renderField() не вызывается.

Как сделать повторное рендеринг ListView при изменении состояния нажатием кнопки?

RNPlayNative Link

import React, {Component} from 'react'; 
import { 
    AppRegistry, 
    View, 
    ListView, 
    Text, 
    TouchableOpacity 
} from 'react-native'; 

class SampleApp extends Component { 

    constructor(props) { 
    super(props); 
    var ds = new ListView.DataSource({ 
     rowHasChanged: (row1, row2) => row1 !== row2, 
    }); 
    this.state = { 
     fields: ds.cloneWithRows([ 
     {id:0},{id:1},{id:2} 
     ]), 
     selectedField: {id:0} 
    }; 
    } 

    handleClick(field) { 
    console.log("Selected field:",field); 
    this.setState({ 
     selectedField: field 
    }); 
    } 

    renderField(field) { 
    return (
     <TouchableOpacity onPress={this.handleClick.bind(this, field)} > 
     <View style={{backgroundColor:(this.state.selectedField.id==field.id)?'green':'white'}}> 
      <Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}>{field.id}</Text> 
     </View> 
     </TouchableOpacity> 
    ); 
    } 

    render() { 
    return (
     <View> 
     <ListView 
      dataSource={this.state.fields} 
      renderRow={this.renderField.bind(this)} 
     /> 
     </View> 
    ); 
    } 
} 

AppRegistry.registerComponent('SampleApp',() => SampleApp); 
+0

Попробуйте это: http://stackoverflow.com/questions/26882177/react-js-inline-style-best-practices –

+0

Я уже использую встроенные стили, проблема заключается в динамическом связывании стиля с состоянием в таких событиях, как щелчок. –

ответ

2

Список визуализируется снова при изменении источника данных, а в вашем примере, поскольку dataSource никогда не изменяется, listview никогда не повторно отображается. Этого можно добиться, добавив поле в переменную состояния для хранения данных для источника данных. И в методе componentDidMount, у строк данных dataSource с переменной состояния данных. Всякий раз, когда вы хотите повторно отобразить список, вам придется изменить только переменную состояния данных, и список будет автоматически повторно отображаться. Я изменил ваши данные, чтобы добавить выбранное состояние с каждым объектом. Вот обновленный код.

class SampleApp extends Component { 

    constructor(props) { 
    super(props); 
    var ds = new ListView.DataSource({ 
     rowHasChanged: (row1, row2) => row1 !== row2, 
    }); 
    var dataVar = [ 
     { 
      id:0, 
      selected: true, 
     },{ 
      id:1, 
      selected: false, 
     },{ 
      id:2, 
      selected: false, 
     } 
     ]; 
    this.state = { 
     data: dataVar, 
     fields: ds, 
    }; 
    } 

    componentDidMount() { 

    this.setState({ 
     fields: this.state.fields.cloneWithRows(dataVar) 
    }); 
    } 


    handleClick(field) { 
    console.log(field); 
    field.selected = !field.selected; 

    var dataClone = this.state.data; 
    console.log(dataClone); 

    dataClone[field.id] = field; 

    this.setState({ 
     data: dataClone, 
    }); 
    } 

    renderField(field) { 
    let color = (field.selected == true)?'green':'white'; 
    return (
     <TouchableOpacity onPress={this.handleClick.bind(this, field)} > 
     <View style={{backgroundColor:color}}> 
      <Text style={{left:0, right:0, paddingVertical:50,borderWidth:1}}>  {field.id}</Text> 
     </View> 
     </TouchableOpacity> 
    ); 
    } 

    render() { 
    return (
     <View> 
     <ListView 
      dataSource={this.state.fields} 
      renderRow={(field) => this.renderField(field)} 
     /> 
     </View> 
    ); 
    } 
} 

Вот рабочая rnplay sample

+0

Вы забыли исправить эту строку внутри 'componentDidMount':' fields: this.state.fields.cloneWithRows (this.state.data) ' –

+0

Я пробовал решение, но по какой-то причине я не могу вызвать' renderField() 'функция обновления данных. 'handleClick()' работает правильно, и 'data' обновляется. –

+0

Хорошо, я дошел до того, что он работает. Мое приложение имело эту строку: 'if (! This.state.loaded) { return this.renderLoadingView(); } 'для откладывания рендеринга представления до тех пор, пока не загрузятся данные, которые по какой-то причине заблокировали вызов renderField(). –

0

Здесь было бы мое решение вопроса, но она по-прежнему занимает слишком много времени, чтобы обработать каждый клик:

handleClick(field) { 
    newFields = this.state.fields.map((x) => x.key === field.key && x.active !== true ? {...x,active:true} : {...x,active:false}) 
    this.setState({ 
    fields:newFields, 
    dataSource: this.state.dataSource.cloneWithRows(newFields) 
    }); 
}