反应本机-状态未正确更新

时间:2018-08-24 12:24:58

标签: javascript reactjs react-native native

您好,我实际上是在构建一个记事应用程序,您可以在其中将一些记事添加到日历中的特定日期。

我在日历中使用了wix-agenda组件。 单击灰色复选框时,我更新了要检查的项目的状态,但该状态未得到更新。 当我再次将文件保存在编辑器中(使用Hotload)时,组件会更新,并且复选框显示为黄色。有人提示吗?

const SCREEN_WIDTH = Dimensions.get('window').width;
const SCREEN_HEIGHT = Dimensions.get('window').height;

const customAnimation = {
  duration: 100,
  create: {
    type: LayoutAnimation.Types.linear,
    property: LayoutAnimation.Properties.opacity,
  },
  update: {
    type: LayoutAnimation.Types.linear,
  }
};

class CalendarScreen extends Component {
    constructor(props) {
        super(props);

        this.state = {
          items: {
            '2018-08-20': [
            {key: '2018-08-20', name: 'Test', checked: true },
            {key: '2018-08-20', name: 'Test', checked: false },
            {key: '2018-08-20', name: 'Test', checked: false },
          ],
          '2018-08-21': [

          ],
          '2018-08-22': [
            {key: '2018-08-22', name: 'Test!', checked: true },
            {key: '2018-08-22', name: 'Test', checked: false },
            {key: '2018-08-22', name: 'Test', checked: true },
          ],
        },
          reason: '',
          itemsOld: {},
          isModalVisible: false,
          noteDate: new Date(),
          noteText: '',
          isLoading: false
        };
      }
      /* async componentWillMount() {
        let notes = await AsyncStorage.getItem('notes');
        if (!_.isNull(notes)) {
          console.log('>>>>>>>>'+ notes)
          this.setState({ items: notes, isLoading: false });
          console.log("###### MOUNT #######");
          console.log("ITEMS: >>> "+ this.state);
        }
      }*/

      componentWillUpdate() {
        LayoutAnimation.linear();
        LayoutAnimation.configureNext(customAnimation);
      }

      /*async componentWillUnmount() {
        await AsyncStorage.setItem('notes', JSON.stringify(this.state.items));
      }*/

      onToastClose(reason) {
        this.setState({ reason });
        if (reason === 'user') {
          this.setState({ items: this.state.itemsOld });
        }
      }


      setDate(newDate) {
        newDate.setDate(newDate.getDate()+1);
        date = newDate.toISOString().split('T')[0];
        this.setState({ noteDate: date });
      }

      loadItems(day) {

        // console.log(`Load Items for ${day.year}-${day.month}`);
      }

  addNote() {
    oldState = { ...this.state.items };
    arrayToPush = oldState[this.state.noteDate];
    if (_.isNil(arrayToPush)) {
        arrayToPush = [];
    }
      arrayToPush.push({key: this.state.noteDate, name: this.state.noteText, checked: false });
    oldState[this.state.noteDate] = arrayToPush;
    this.setState({ items: oldState, noteText: '', isModalVisible: false });
  }

  removeItem(item) {
    //Copy state
    oldState = { ...this.state.items };
    //Get actual clicked key -> date of note is the key
    actualArray = [...this.state.items[item.key]];

    // Get the index in the Array with the notes
    index = actualArray.indexOf(item);

    //remove the object from the array!!
    actualArray.splice(index,1);

    //Copy previous state
    newState = { ...this.state.items };

    //Update array with key of clicked element
    newState[item.key] = actualArray;

    Toast.show({
      text: 'Sie haben eine Notiz entfernt!',
      buttonText: 'Rückgangig',
      duration: 3000,
      onClose: this.onToastClose.bind(this)
    });
    //Update state --- MAGIC!
    this.setState({ items:  newState, itemsOld: oldState });
  }

  toggleCheck(item) {
    //Get actual clicked key -> date of note is the key
    actualArray = [...this.state.items[item.key]];
    // Get the index in the Array with the notes
    index = actualArray.indexOf(item);

    //change the checkmark!!
    actualArray[index].checked = !actualArray[index].checked;

    //Copy previous state
    newState = { ...this.state.items };

    //Update array with key of clicked element
    newState[item.key] = actualArray;

    //Update state --- MAGIC!
    this.setState({ items:  newState });
  }

  _toggleModal = () => {

    this.setState({ isModalVisible: !this.state.isModalVisible });
  }


  rowHasChanged(r1, r2) {
    return r1.name !== r2.name;
  }

  timeToString(time) {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
  }
  renderDay(day,item) {
    if (day) {
    return (
    <View style={styles.day}>
      <Text allowFontScaling={false} style={[styles.dayNum]}>{day.day }</Text>
      <Text allowFontScaling={false} style={[styles.dayText]}>{day.text}</Text>
    </View>
    );
      }
      return (
          <View style={styles.day}/>
        );
      }

  renderEmptyDate() {a
    return (
      <View style={styles.emptyDate}><Container><Text>This is empty date!</Text></Container></View>
    );
  }

  renderItem(item) {
    color = item.checked ? "#F7D23D" : '#ccc';
    return (
        <Container
        style={[styles.item, { height: 70, flexDirection: 'row', alignItems: 'center' }]}
        >
          <Body style={{ flex: 5 }}>
            <Text>{item.name}</Text>
          </Body>
          <Body style={{ flex: 1 }}>
            <MaterialIcons
            size={24} name="check-circle" color={color}
            style={{ alignSelf: 'center', }}
            onPress={() => {
              this.toggleCheck(item);              
            }}
            />
          </Body>
        </Container>
    );
  }

  render() {
    if (this.state.isLoading) {
      return <View><Text>Loading...</Text></View>;
    }
    return (
      <Container>
            <Header textStyle={{ color: 'white' }}>
            <Left >
            <Button light transparent style={styles.whiteIcon} onPress={() => this.props.navigation.dispatch(DrawerActions.openDrawer())}>
              <Icon name='ios-menu' />
            </Button>
            </Left>
            <Body>
                <Title style={styles.headerTextStyle}> KALENDER </Title>
            </Body>
            <Right>
                <Button light transparent>
                <Icon name='search' />
                </Button>
            </Right>
            </Header>
            <Container>
      <Agenda
        //https://github.com/wix/react-native-calendars
        items={this.state.items}
        loadItemsForMonth={this.loadItems.bind(this)}
        selected={'2018-08-20'}
        renderItem={this.renderItem.bind(this)}
        renderEmptyDate={() => {return (<View />);}}
        renderEmptyData = {() => {return (<View />);}}
        rowHasChanged={this.rowHasChanged.bind(this)}
         theme={{ selectedDayBackgroundColor: '#F7D23D', todayTextColor: '#F7D23D', dotColor: '#F7D23D',}}
         renderDay={this.renderDay.bind(this)}
      />
          <Modal
          avoidKeyboard
          isVisible={this.state.isModalVisible}
          animationType="fade"
          onBackdropPress={() => this._toggleModal()}
          onBackButtonPress={() => this._toggleModal()}
          style={{ justifyContent: 'flex-end'}}
          backdropOpacity={0.5}
          >
          <Card>
            <CardItem header>
              <Text>Notiz erstellen</Text>
            </CardItem>
            <CardItem>
            <Form style={{ flex: 1}}>
            <DatePicker
            defaultDate={new Date(2018, 8, 20)}
            minimumDate={new Date(2018, 1, 1)}
            maximumDate={new Date(2018, 12, 31)}
            locale={"de"}
            modalTransparent={false}
            animationType={"fade"}
            androidMode={"default"}
            placeHolderText="Datum wählen"
            placeHolderTextStyle={{ color: "#d3d3d3" }}
            onDateChange={this.setDate.bind(this)}
            />
            <Textarea rowSpan={3} placeholder="Notiz" value={this.state.noteText} onChangeText={text => this.setState({ noteText: text })} />
          </Form>
            </CardItem>
            <CardItem footer>
            <Left>
              </Left>
              <Body>
              <Button transparent onPress={()=>{this._toggleModal()}}>
                  <Text>Abbrechen</Text>
                </Button>
              </Body>
              <Right>
              <Button transparent onPress={this.addNote.bind(this)}>
                <Text>Hinzufügen</Text>
                </Button>
              </Right>
            </CardItem>
          </Card>
          </Modal>
      <Fab
            style={{ backgroundColor: '#F7D23D' }}
            position="bottomRight"
            onPress={() => {
              this.setState({ active: !this.state.active });

              this._toggleModal();
              }}
            >
            <MaterialIcons size={24} name="add" />
          </Fab>
      </Container>  
      </Container>
    );
  }

  //COMPONENT END
}


const styles = StyleSheet.create({
  item: {
    backgroundColor: 'white',
    flex: 1,
    borderRadius: 5,
    padding: 10,
    marginRight: 10,
    marginTop: 10

  },
  emptyDate: {
    height: 15,
    flex:1,
    paddingTop: 30
  },
  dayNum: {
    fontSize: 28,
    fontWeight: '200',
    color: 'black'
  },
  dayText: {
    fontSize: 14,
    fontWeight: '300',
    color: 'black',
    marginTop: -5,
    backgroundColor: 'rgba(0,0,0,0)'
  },
  day: {
    width: 63,
    alignItems: 'center',
    justifyContent: 'flex-start',
    marginTop: 32
  },
});

export default CalendarScreen;

主要部分在这里

 toggleCheck(item) {
    //Get actual clicked key -> date of note is the key
    actualArray = [...this.state.items[item.key]];
    // Get the index in the Array with the notes
    index = actualArray.indexOf(item);

    //change the checkmark!!
    actualArray[index].checked = !actualArray[index].checked;

    //Copy previous state
    newState = { ...this.state.items };

    //Update array with key of clicked element
    newState[item.key] = actualArray;

    //Update state --- MAGIC!
    this.setState({ items:  newState });
  }

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

let方法内声明的局部变量似乎缺少关键字consttoggleCheck,导致分配给全局变量而不是回调局部变量—特别是,变量actualArrayindexnewState在这些回调的所有调用中都是共享的。

方法setDateaddNoteremoveItemrenderItem中也是如此。

这是解决toggleCheck的方法:

toggleCheck(item) {
  const actualArray = [...this.state.items[item.key]];
  const index = actualArray.indexOf(item);
  actualArray[index].checked = !actualArray[index].checked;

  const newState = { ...this.state.items };
  newState[item.key] = actualArray;

  this.setState({ items: newState });
}