【问题标题】:Changing the style of "toggled" elements in a list, react-native更改列表中“切换”元素的样式,react-native
【发布时间】:2019-02-14 07:05:38
【问题描述】:

我无法更改列表中只有一个元素的样式。 下面是我的Main 类,以及StationDetails 类,这是我创建的用于逐个渲染列表元素的组件。

StationDetails 中有一行(第 31 行)我似乎无法找出问题所在。我想根据元素的 ID 是否包含在 activeStations 列表中来设置组件的样式。

这是一行:

 style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}

这是我的Main 课程

import React, { Component } from "react"
import axios from "axios"
import { Text, View, ScrollView } from "react-native"
import StationDetails from "./StationDetails"

class Main extends Component {
  constructor(props) {
    super(props)
    this.state = { stations: [], pressStatus: false, activeStations: [] }
    this.handleClick = this.handleClick.bind(this)
  }

  componentWillMount() {
    axios
      .get("https://api.citybik.es/v2/networks/trondheim-bysykkel")
      .then(response =>
        this.setState({ stations: response.data.network.stations })
      )
  }

  handleClick() {
    this.setState({ pressStatus: !this.state.pressStatus })
  }

  renderStations() {
    return this.state.stations.map(stations => (
      <StationDetails
        activeStations={this.state.activeStations}
        handleClick={this.handleClick}
        pressStatus={this.state.pressStatus}
        key={stations.id}
        stations={stations}
      >
        {stations.name}
      </StationDetails>
    ))
  }

  render() {
    return (
      <ScrollView style={{ flex: 1, marginTop: 20 }}>
        {this.renderStations()}
      </ScrollView>
    )
  }
}

export default Main

这是我的StationDetails 组件。

import React from "react"
import { Text, View } from "react-native"
import Card from "./felles/Card"
import CardSection from "./felles/CardSection"
import Button from "./felles/Button"

const StationDetails = ({
  stations,
  handleClick,
  pressStatus,
  activeStations
}) => {
  const {
    headerTextStyle,
    leftPartStyle,
    rightPartStyle,
    pressedStyle,
    buttonStyle
  } = styles

  return (
    <Card style={{ flex: 1, flexDirection: "row" }}>
      <CardSection style={leftPartStyle}>
        <Text style={headerTextStyle}>
          {stations.name}
        </Text>
        <Text>
          Free bikes: {stations.free_bikes}
        </Text>
      </CardSection>
      <CardSection style={rightPartStyle}>
        <Button
          onPress={() => {
            if (!activeStations.includes(stations.id)) {
              activeStations.push(stations.id)
            } else {
              activeStations.splice(activeStations.indexOf(stations.id), 1)
            }
          }}
          style={
            activeStations.includes(stations.id) ? pressedStyle : buttonStyle
          }
        >
          Abonner
        </Button>
      </CardSection>

    </Card>
  )
}

const styles = {
  textStyle: {
    fontSize: 14
  },
  leftPartStyle: {
    flex: 3,
    flexDirection: "column",
    justifyContent: "space-between"
  },
  rightPartStyle: {
    flex: 1
  },
  pressedStyle: {
    backgroundColor: "green"
  },
  headerTextStyle: {
    fontSize: 18
  },
  thumbnailStyle: {
    height: 50,
    width: 50
  },
  buttonStyle: {
    backgroundColor: "#fff"
  }
}

export default StationDetails

【问题讨论】:

    标签: reactjs list react-native styles state


    【解决方案1】:

    您试图从StationDetails 设置Main.activeStations 的状态,这是不可取的。有几点需要注意

    • Main 的activeStations 处于其本地组件级别状态。
    • 您不应该尝试从子组件中改变它。
    • 由于您将变异的 activeStations 状态从 StationDetails 分配给 Main.activeStations,因此 ReactNative (RN) 在其协调过程中没有发现状态差异,因此不会重新渲染 StationDetails
    • 我们需要 RN 重新渲染 StationDetails 以便它为按钮等显示正确的样式。
    • setState 上的文档

    我会这样做

    • Main渲染StationDetails
    • StationDetails 获取所选电台的回调
    • Main 负责改变它自己的内部状态 (activeStations)

    通过这种方式,

    • StationDetails 仅负责渲染给定道具的电台列表,不负责其他任何事情。这是一个呈现列表的愚蠢组件。
    • Main 负责处理自己的内部状态

    结果如下:

    Main.js

    import React, { Component } from 'react';
    import axios from 'axios';
    import { ScrollView } from 'react-native';
    import StationDetails from './StationDetails';
    
    export default class App extends Component {
      constructor(props) {
        super(props);
    
        this.onSelectStation = this.onSelectStation.bind(this);
    
        this.state = {
          stations: [],
          pressStatus: false,
          activeStations: []
        };
      }
    
      componentWillMount() {
        axios.get('https://api.citybik.es/v2/networks/trondheim-bysykkel')
          .then(response => this.setState({ stations: response.data.network.stations }));
      }
    
      onSelectStation(stationKey) {
        const { activeStations } = this.state;
        const activeStationsEdit = activeStations;
    
        if (!activeStations.includes(stationKey)) {
          activeStationsEdit.push(stationKey);
        } else {
          activeStationsEdit.splice(activeStations.indexOf(stationKey), 1);
        }
    
        this.setState({ activeStations: activeStationsEdit });
      }
    
      renderStations() {
        return this.state.stations.map((stations) =>
          <StationDetails
            activeStations={this.state.activeStations}
            pressStatus={this.state.pressStatus}
            key={stations.id}
            stations={stations}
            stationId={stations.id}
            onSelectStation={this.onSelectStation}
          >
            {stations.name}
          </StationDetails>
        );
      }
    
    
      render() {
        return (
          <ScrollView style={{ flex: 1, marginTop: 20 }}>
            {this.renderStations()}
          </ScrollView>
        );
      }
    }
    

    StationDetails

    import React from 'react';
    import { Text, View, TouchableOpacity } from 'react-native';
    
    const StationDetails = ({ stations, activeStations, stationId, onSelectStation }) => {
        const { headerTextStyle, leftPartStyle, container, pressedStyle, buttonStyle } = styles;
    
        return (
            <View style={container}>
                <View style={leftPartStyle}>
                    <Text style={headerTextStyle}>
                        {stations.name}
                    </Text>
                    <Text>
                        Free bikes: {stations.free_bikes}
                    </Text>
                </View>
                <TouchableOpacity
                    onPress={() => onSelectStation(stationId)}
                    style={activeStations.includes(stations.id) ? pressedStyle : buttonStyle}
                />
            </View>
        );
    }
    
    const styles = {
        container: {
            flex: 1,
            flexDirection: 'row',
            marginBottom: 10
        },
        leftPartStyle: {
            flex: 3,
            flexDirection: 'column',
            justifyContent: 'space-between'
        },
        pressedStyle: {
            backgroundColor: 'green',
            flex: 1,
        },
        headerTextStyle: {
            fontSize: 18
        },
        buttonStyle: {
            backgroundColor: 'skyblue',
            flex: 1,
        }
    };
    
    export default StationDetails;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-31
      • 1970-01-01
      相关资源
      最近更新 更多