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

Posted

技术标签:

【中文标题】React Native - 从父组件重新渲染子组件【英文标题】:React Native - rerender child component from parent component 【发布时间】:2019-02-26 03:18:40 【问题描述】:

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

父.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);
    

....

Child.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
          ....

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

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,但就在它下面)和仍然什么也没做。

更新

日历在模式上,我没有任何处理程序来更新它的状态,这可能是问题吗?

更新

我在文档中找到了这个:

!免责声明!确保markedDates 参数是不可变的。如果你 更改markedDates 对象的内容,但对它的引用没有 不会触发更改日历更新。

这是什么意思?

更新

我试图用一些谷歌搜索来解释这意味着什么,这是否使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);

上面的输出是:

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

我可以看到状态对象markedDays 在此输出中每按一次按钮就变大,为什么样式没有改变?

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

【问题讨论】:

你不应该做这样的事情 this.state.markedDays = mappedDaysHolder.始终使用 setState 来更新状态对象。使用 setState 重新渲染组件和所有子组件。 感谢好收获,我做出了改变,但没有运气,用我发现的其他东西更新我的问题 使用 React.PureComponent 并在构造函数 constructor() super(); 中定义你的状态this.state = .... this.markedDays: , someVar: 0 ; this.handler = this.handler.bind(this); this.markedDays = ; 你的意思是this.state = .... this.markedDays: ?你的意思是this.state = .... markedDays: ?还是我应该在该州使用它? 构造函数() super(); this.state = defineStateVariablesHere: true 【参考方案1】:

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

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,
    )
  

【讨论】:

【参考方案2】:

这是我试图做的事情的冲洗答案。我希望能够通过按下日期来选择和取消选择日期(在@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');
    

....

【讨论】:

以上是关于React Native - 从父组件重新渲染子组件的主要内容,如果未能解决你的问题,请参考以下文章

为啥组件在状态更改后不重新渲染。在 react-native 函数组件中

如何在 react-native 中重新渲染组件?

React Native - 状态改变但组件没有重新渲染

如何使用 redux 让根组件在 react-native 中重新渲染(开源项目)

React Native this.setState() 仅在再次与组件交互后重新渲染

React Native:更新数据后未重新渲染组件