首页 > 解决方案 > 使用自定义按钮反应 Native FlatList,如何在点击时更改颜色?

问题描述

我创建了一个呈现名称的 FlatList。每行都有自己的按钮。单击按钮时,名称将添加到列表中,并且按钮应更改颜色

我的问题是,当我单击按钮时,按钮不会改变颜色,它只会在我对 FlatList 进行拉刷新时改变颜色

使用我的零食:https ://snack.expo.io/@thesvarta/92f850

这是我的组件

  import React, { Component } from 'react';
  import { connect } from 'react-redux';
  import {
    View,
    Text,
    FlatList,
    StatusBar,
    StyleSheet,
    ActivityIndicator,
    TouchableOpacity,
    TouchableHighlight,
    Image,
    Button,
    SearchBar,
    TextInput,
  } from 'react-native';
  import TextDetails from '../TextDetails/TextDetails';
  import { selectOptions } from '../store/actions/index';
  class Search extends Component {
    constructor(props) {
      super(props);

      this.state = {
        loading: false,
        data: [],
        page: 1,
        error: null,
        refreshing: false,
        groupBy: '',
      };
    }
    setFetch = () => {
      this.setState(
        {
          groupBy: this.props.GroupBy,
        },
        () => {
          this.makeRemoteRequest();
        }
      );
    };
    componentDidMount() {
      this.setFetch();
    }

    makeRemoteRequest = () => {
      const { page, groupBy } = this.state;
      const url = `https://ollenorstrom.se/ollenorstrom.se/avoka/api/getOptions.php?page=${page}&row_per_page=5&group_by=${groupBy}`;
      fetch(url)
        .then(response => response.json())
        .then(responseJson => {
          this.setState(
            {
              data:
                page == 1
                  ? responseJson[0].DATA
                  : [...this.state.data, ...responseJson[0].DATA],
              status: responseJson[0].STATUS,
              message: responseJson[0].MESSAGE,
              isLoading: false,
              refreshing: false,
            },
            () => {}
          );
        });
    };
    handleRefresh = () => {
      this.setState(
        {
          page: 1,
          refreshing: true,
        },
        () => {
          this.makeRemoteRequest();
        }
      );
    };

    handleLoadMore = () => {
      this.setState(
        {
          page: this.state.page + 1,
        },
        () => {
          this.makeRemoteRequest();
        }
      );
    };

    renderSeparator = () => {
      return (
        <View
          style={{
            height: 1,
            width: '86%',
            backgroundColor: '#CED0CE',
            marginLeft: '14%',
          }}
        />
      );
    };
    inArray = (needle, haystack) => {
      let length = haystack.length;
      for (let i = 0; i < length; i++) {
        if (haystack[i] == needle) return true;
      }
      return false;
    };
    renderRow = ({ item, index }) => {
      return (
        <View style={styles.ListContainer}>
          <View style={styles.Text}>
            <TextDetails Size={18}>{item.name}</TextDetails>
          </View>
          <View style={styles.button}>
            <TouchableOpacity
              style={
                this.inArray(item.name, this.props.selectedOptions)
                  ? styles.buttonOrange
                  : styles.buttonGray
              }
              onPress={() => this.props.onSelectOptions(item.name)}
            />
          </View>
        </View>
      );
    };
    renderFooter = () => {
      if (!this.state.loading) return null;

      return (
        <View
          style={{
            paddingVertical: 20,
            borderTopWidth: 1,
            borderColor: '#CED0CE',
          }}>
          <ActivityIndicator animating size="large" />
        </View>
      );
    };
    render() {
      return (
        <View style={styles.SearchContatiner}>
          <View style={styles.Search}>
            <View style={styles.ImageIcon}>
              <Image
                style={styles.Image}
                resizeMode="contain"
                source={require('../images/sokbla.png')}
              />
            </View>
            <View style={styles.InputBox}>
              <TextInput
                style={styles.InputText}
                onChangeText={text => this.setState({ query: text })}
                placeholder={'Search for ' + this.props.Title}
                value={this.state.query}
              />
            </View>
            <TouchableOpacity
              onPress={() => alert(this.props.selectedOptions)}
              style={styles.KryssIcon}>
              <Image
                style={styles.ImageKryss}
                resizeMode="contain"
                source={require('../images/kryssbla.png')}
              />
            </TouchableOpacity>
          </View>
          <View style={styles.Lista}>
            <FlatList
              style={styles.Flatlist}
              data={this.state.data}
              renderItem={this.renderRow}
              keyExtractor={(item, index) => index.toString()}
              ItemSeparatorComponent={this.renderSeparator}
              ListFooterComponent={this.renderFooter}
              onRefresh={this.handleRefresh}
              refreshing={this.state.refreshing}
              onEndReached={this.handleLoadMore}
              onEndReachedThreshold={0.5}
            />
          </View>
        </View>
      );
    }
  }
  const styles = StyleSheet.create({
    button: {
      width: '20%',
      justifyContent: 'center',
      alignItems: 'center',
    },
    buttonGray: {
      width: 25,
      height: 25,
      borderRadius: 12.5,
      backgroundColor: 'gray',
    },
    buttonOrange: {
      width: 25,
      height: 25,
      borderRadius: 12.5,
      backgroundColor: 'orange',
    },
    Lista: {
      marginTop: 20,
    },
    Flatlist: {
      width: '100%',
      height: 300,
    },
    ListContainer: {
      flexDirection: 'row',
      width: '100%',
      height: 40,
    },
    Text: {
      marginLeft: '10%',
      width: '70%',
      justifyContent: 'center',
    },
    SearchContatiner: {},
    Search: {
      width: '100%',
      height: 60,
      backgroundColor: 'rgb(240,240,240)',
      flexDirection: 'row',
    },
    Image: {
      width: 23,
      height: 33,
    },
    ImageIcon: {
      justifyContent: 'center',
      width: '15%',
      alignItems: 'center',
    },
    InputBox: {
      width: '70%',
      justifyContent: 'center',
    },
    InputText: {
      paddingLeft: 20,
      width: '100%',
      height: 50,
      fontSize: 20,
    },
    KryssIcon: {
      justifyContent: 'center',
      width: '15%',
      alignItems: 'center',
    },
    ImageKryss: {
      width: 18,
      height: 28,
    },
  });
  const mapStateToProps = state => {
    return {
      selectedOptions: state.filter.selectedOptions,
    };
  };
  const mapDispatchToProps = dispatch => {
    return {
      onSelectOptions: name => dispatch(selectOptions(name)),
    };
  };
  export default connect(
    mapStateToProps,
    mapDispatchToProps
  )(Search);

这是我的行动

    import { OPTIONS_SELECT } from './actionTypes';

    export const selectOptions = name => {
      return {
        type: OPTIONS_SELECT,
        selectedOptions: name,
      };
    };

还有我的减速机

    import {
      OPTIONS_SELECT,
    } from '../actions/actionTypes';

    const initialState = {
      selectedOptions:[],
    };

    const reducer = (state = initialState, action) => {
      switch (action.type) {
        case OPTIONS_SELECT:
          return {
            ...state,
            selectedOptions: [...state.selectedOptions, action.selectedOptions],
          };
        default:
          return state;
      }
    };
    export default reducer;

标签: javascriptreact-nativereact-reduxreact-native-flatlist

解决方案


缺少组件的extraData属性:FlatList

通过将 extraData={this.state} 传递给 FlatList,我们确保 FlatList 本身会在 state.selected 更改时重新渲染。如果不设置这个 prop,FlatList 将不知道它需要重新渲染任何项目,因为它也是一个 PureComponent,并且 prop 比较不会显示任何更改。

链接到文档:https ://facebook.github.io/react-native/docs/flatlist

此属性FlatList在传递的对象更新时更新。在您的情况下,您需要通过:

extraData={this.props.selectedOptions}

这是您的零食的工作演示


推荐阅读