繁体   English   中英

React Native - 从父组件重新渲染子组件

[英]React Native - rerender child component from parent component

我正在尝试修改日历 - https://github.com/wix/react-native-calendars以便当我按下一天时,背景和文本 colors 会在那天发生变化。 我读到要重新渲染一个组件,您需要更新父组件的 state,这就是我正在尝试的:

父类.js

export default class InitiateRent extends Component {
  state = {
    ....
    this.markedDays: {},
    someVar: 0
  };

  constructor() {
    super(); 
    this.handler = this.handler.bind(this);
    this.markedDays = {};
  }

  ....

  handler(e) {
    console.log('handler running');
    this.setState({
      someVar: 123
    })
  }

  <Calendar 
    handler={this.handler}
    markedDates={this.markedDays}
    onDayPress={(day)=> {
      console.log('selected day', day);

      var dateString = `'${day.year}-${day.month}-${day.day}'`

      var addDate = {
        [dateString]: {
          customStyles: {
            container: {
              backgroundColor: '#6de3dc',
            },
            text: {
              color: 'white',
              fontWeight: 'bold'
            },
          },
        }
      }

      this.markedDays = Object.assign(addDate, this.markedDays);

      console.log(this.markedDays);
    }}

....

子.js

pressDay(date) {
    this.props.handler();
    this._handleDayInteraction(date, this.props.onDayPress);
}

renderDay(day, id) { //GETS CALLED IN CHILD RENDER METHOD VIA AN INTERMEDIARY
    ....
        <DayComp
          ....
          onPress={this.pressDay}
          ....
}

一切正常,除了我没有得到预期的结果 - 当我按日历上的日期时,处理程序触发, state 发生变化,并且在控制台中我的 object 看起来正确:

Object

'2018-9-23': {customStyles: {container: {backgroundColor: "#6de3dc"}, text: {color: "white", fontWeight: "bold"}}}

'2018-9-26': {customStyles: {container: {backgroundColor: "#6de3dc"}, text: {color: "white", fontWeight: "bold"}}}

'2018-9-28': {customStyles: {container: {backgroundColor: "#6de3dc"}, text: {color: "white", fontWeight: "bold"}}}

'2018-9-29': {customStyles: {container: {backgroundColor: "#6de3dc"}, text: {color: "white", fontWeight: "bold"}}}

但是日历上当天的背景没有改变,文本也没有改变——我需要做什么才能让它重新呈现(改变)?

更新

我创建了一系列处理程序,从最底层的day组件开始,它只代表日历上的一天,一直到最高级的父视图(不是 App.js,但就在它下面),但仍然什么也没做。

更新

日历是模态的,我没有任何更新其 state 的处理程序,这可能是问题所在吗?

更新

我在文档中找到了这个:

.免责声明。 确保 markedDates 参数是不可变的。 如果您更改 markedDates object 内容但对其的引用未更改,则不会触发日历更新。

这是什么意思?

更新

我试图通过一些谷歌搜索来解释这意味着什么,这会使this.state.markedDays不可变吗?:

                const markedDays = this.state.markedDays;

                var dateString = `'${day.year}-${day.month}-${day.day}'`;

                var addDate = {
                  [dateString]: {
                    customStyles: {
                      container: {
                        backgroundColor: '#6de3dc',
                      },
                      text: {
                        color: 'white',
                        fontWeight: 'bold'
                      },
                    },
                  }
                }

                const markedDaysHolder = {
                  ...markedDays,
                  ...addDate
                }
                
                this.state.markedDays = markedDaysHolder;

更新

我放:

componentDidUpdate(prevProps, prevState, snapshot) {
  console.log("componentDidUpdate in InitiateRent:", prevProps, prevState, snapshot);
}

上面的output是:

componentDidUpdate in InitiateRent: (3) (index.bundle, line 761)

{initiateRentMessage: function, modalHeight: 200, modalWidth: 200, handler: function}

{modalVisible: true, message: "Hi, I would like to rent an item from you.", rentButtonBackground: "#6de3dc", someVar: 123, markedDays: Object}

undefined

我可以从这个 output 看到 state object markedDays随着每次按下按钮而变大,为什么样式没有改变?

在所有相关组件中,我注意到它不会在最低阶组件上触发,这是需要更改的组件。

我也有这个问题,这是你需要做的

constructor(props) {
    super(props)
    this.state = {
    }
    this.onDayPress = this.onDayPress
  }

showCalendar = () => {
    return (
      <Calendar
        onDayPress={this.onDayPress}
        style={styles.calendar}
        hideExtraDays
        markedDates={{
          [this.state.selected]: {
            selected: true,
            disableTouchEvent: true,
            selectedDotColor: 'orange',
          },
        }}
      />
    )
  }

onDayPress = day => {
    this.setState({
      selected: day.dateString,
    })
  }

这是我试图做的事情的冲洗答案。 我希望能够通过按下它来选择和取消选择日期(在@HaiderAli 帮助之后取消选择是问题):

我所要做的就是:

onDayPress = (day) => {
  const _selectedDay = day.dateString;
  let marked = true;
  if (this.state._markedDates[_selectedDay]) {
    // Already in marked dates, so reverse current marked state
    marked = !this.state._markedDates[_selectedDay].selected;
    console.log('marked:', marked);
  }
          
  // Create a new object using object property spread since it should be immutable
  // Reading: https://davidwalsh.name/merge-objects
  const updatedMarkedDates = {
    ...this.state._markedDates,
    ...{
      [_selectedDay]: {
        'selected': marked,
        customStyles: {
          container: {
            backgroundColor: '#6de3dc',
          },
          text: {
            color: 'white',
            fontWeight: 'bold'
          },
        },
      }
    }
  }

  // Triggers component to render again, picking up the new state
  this.setState({ _markedDates: updatedMarkedDates });
}

我添加了'selected': ,它需要在那里,这个功能改进了@HaiderAli 的答案。

为了得到取消选择工作,开node_modules/react-native-calendars/src/calendar/day/custom/index.js (这是你的错了文件,如果你不使用markingType={'custom'}支撑上日历。如果您不使用道具,请编辑node_modules/react-native-calendars/src/calendar/day/basic/index.js )。 进行此更改:

....

render() {
    let containerStyle = [this.style.base];
    let textStyle = [this.style.text];

    let marking = this.props.marking || {};
    if (marking && marking.constructor === Array && marking.length) {
      marking = {
        marking: true
      };
    }
    const isDisabled = typeof marking.disabled !== 'undefined' ? marking.disabled : this.props.state === 'disabled';

    console.log('marking in day:', marking.selected);

    if (marking.selected) {
      containerStyle.push(this.style.selected);
    } else if (isDisabled) {
      textStyle.push(this.style.disabledText);
    } else if (this.props.state === 'today') {
      containerStyle.push(this.style.today);
      textStyle.push(this.style.todayText);

    /********ADD THIS CONDITION********/
    } else if(!marking.selected) { 
      textStyle.push({backgroundColor: '#ffffff', color: '#2d4150'});
    }

....
import { View, Text, StyleSheet } from 'react-native';
import React, { useState, useEffect } from 'react';
import { Calendar, CalendarList, Agenda } from 'react-native-calendars';

const Calender = () => {
  const [selectedDay, setSelectedDay] = useState();

  return (
    <View style={{ flex: 1, backgroundColor: 'white' }}>
      <Calendar
        style={[styles.calendar, { height: 350 }]}
        onDayPress={(day) => {
          setSelectedDay({ selected: day.dateString });
        }}
        enableSwipeMonths={true}
        markedDates={{
          [selectedDay?.selected]: {
            selected: true,
            disableTouchEvent: true,
            selectedDotColor: 'orange',
          },
        }}
      />
    </View>
  );
};

export default Calender;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM