React Native Calendars:如何仅更改议程中一项的背景?

React Native Calendars : How to change the background of only one item in an agenda?

我试图只更改此议程中一个项目的背景,但使用我的代码,当我单击一个项目时,它会更改所有项目的背景颜色,而不仅仅是我单击的项目的背景颜色:screen before clicking on item screen after clicking

问题在于只知道如何更改议程中一个项目的样式,而不是所有项目的样式。

这是我的代码:

import React, { useState } from 'react';
import {
    StyleSheet,
    Text,
    View,
    TouchableOpacity,
} from 'react-native';
import moment from 'moment';
import { Avatar, Card } from 'react-native-paper';
import {Agenda} from "react-native-calendars";

const timeToString = (time) => {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
};


export default function calendarScreen () {


    const [color, setColor] = useState(
        {backgroundColor: 'white', backgroundColor2: 'white', texte: 'Disponible', pressed: false}
    );

    const changeColor = () => {
        if (!color.pressed) {
            setColor({backgroundColor: 'lightgreen', backgroundColor2: 'white', texte: 'Réservé', pressed: true})
        } else {
            setColor({backgroundColor: 'white', backgroundColor2: 'green', texte: 'Disponible', pressed: false})
        }

    };

    const [items, setItems] = useState({});

    const loadItems = (day) => {
        setTimeout(() => {
            for (let i = -15; i < 85; i++) {
                const time = day.timestamp + i * 24 * 60 * 60 * 1000;
                const strTime = timeToString(time);

                if (!items[strTime]) {
                   items[strTime] = [];
                    const numItems = 1;
                    for (let j = 0; j < numItems; j++) {
                        items[strTime].push({
                            name: 'Disponible',
                            height: Math.max(50, Math.floor(Math.random() * 150)),
                            style: color.backgroundColor
                        });
                    }
                }
            }
            const newItems = {};
            Object.keys(items).forEach(key => {newItems[key] = items[key];});
            setItems(newItems);
        }, 1000);
    };


    
    const renderItem = (item, firstItemInDay) => {
        return (
            <TouchableOpacity style={{ marginTop: 17, marginRight: 10}} onPress={(changeColor)}>
                <Card style={ { backgroundColor : color.backgroundColor }}>
                    <Card.Content>
                        <View style={{
                            flexDirection: 'row',
                            justifyContent: 'space-between',
                            alignItems: 'center',
                        }}>
                            <Text>{item.name}</Text>
                            <Avatar.Text label="J" />
                        </View>
                    </Card.Content>
                </Card>
            </TouchableOpacity>
        )
    };
    return (
        <View style={{flex:1}}>
            <Agenda
                items={items}
                loadItemsForMonth={loadItems}
                selected={'2020-09-23'}
                renderItem={renderItem}
                />
        </View>
    )
}

非常感谢您的帮助

问题是颜色状态绑定到您正在渲染的每个项目。您正在渲染的每个项目都应该知道自己是否处于活动状态,即有自己的状态。

所以你可以这样做:

const activeItemText = 'Réservé';
const activeItemStyles = {
  backgroundColor: 'lightgreen',
  backgroundColor2: 'white',
};
const inactiveItemText = 'Disponible';
const inactiveItemStyles = {
  backgroundColorPrimary: 'white',
  backgroundColorSecondary: 'white',
};

const timeToString = (time) => {
  const date = new Date(time);
  return date.toISOString().split('T')[0];
};

const CalendarItem = ({item, firstItemInDay}) => {
  const [active, setActive] = React.useState(false);
  const changeColor = () => {
    setActive(!active);
  };

  return (
    <TouchableOpacity
      style={{marginTop: 17, marginRight: 10}}
      onPress={changeColor}>
      <Card style={active ? activeItemStyles : inactiveItemStyles}>
        <Card.Content>
          <View
            style={{
              flexDirection: 'row',
              justifyContent: 'space-between',
              alignItems: 'center',
            }}>
            <Text>{active ? activeItemText : inactiveItemText}</Text>
            <Avatar.Text label="J" />
          </View>
        </Card.Content>
      </Card>
    </TouchableOpacity>
  );
};

const renderItem = (item, firstItemInDay) => {
  return <CalendarItem item={item} firstItemInDay={firstItemInDay} />;
};

const App = () => {
  const [items, setItems] = useState({});

  const loadItems = (day) => {
    setTimeout(() => {
      for (let i = -15; i < 85; i++) {
        const time = day.timestamp + i * 24 * 60 * 60 * 1000;
        const strTime = timeToString(time);

        if (!items[strTime]) {
          items[strTime] = [];
          const numItems = 1;
          for (let j = 0; j < numItems; j++) {
            items[strTime].push({
              name: inactiveItemStyles.texte,
              height: Math.max(50, Math.floor(Math.random() * 150)),
            });
          }
        }
      }
      const newItems = {};
      Object.keys(items).forEach((key) => {
        newItems[key] = items[key];
      });
      setItems(newItems);
    }, 1000);
  };

  return (
    <View style={{flex: 1}}>
      <Agenda
        items={items}
        loadItemsForMonth={loadItems}
        selected={'2020-09-23'}
        renderItem={renderItem}
      />
    </View>
  );
};

export default App;

进一步解释上述方法

我将样式和可能的文本值放在任何组件之外,并创建了一个自定义 CalendarItem 组件,该组件传递给您的 renderItem 函数。

因为 CalendarItem 是一个功能组件,它可以有自己的状态。在这个实例中,我们不必将整个对象保存在状态中,因为我们真正想知道的只是一个项目是否处于活动状态。我们可以在按下时更新 active 状态,然后根据您的活动和非活动样式和数据有条件地呈现 CalendarItem