首页 > 解决方案 > Updating this.state with setState doesn't rerender component

问题描述

My code structure is the following: Render function function to return jsx body of my component state.popup with null that is updated with JSX when an button is clicked

inside state.popup I have a form with inputs and a custom date selector. The custom date selector is supposed to be displayed when an icon is clicked with an onClick. When the onClick is ran i set this.state.dateSelector to JSX which is inside the state.popup JSX, but the dateSelector doesn't render.

import React, { Component } from 'react';

import calendarData from './DataHandling';

//CSS
import './Calendar.css';

class Calendar extends Component {

  constructor(props) {
    super(props);

    this.state = {
      popup: [],
      miniCalendar: [],
      create: {
        title: undefined,
        startTime: undefined,
        endTime: undefined,
        date: undefined,
        month: undefined,
        year: undefined
      },
    };

    this.calendarBody = React.createRef();
    this.popup = React.createRef();
    this.createPopup = React.createRef();
    this.closeX = React.createRef();
    this.dateSelectorHolder = React.createRef();
    this.daySelect = React.createRef();
    this.monthSelect = React.createRef();
    this.yearSelect = React.createRef();

    this.resetDate = this.resetDate.bind(this);
    this.createEvent = this.createEvent.bind(this)
  };

  // -- Popup related code --

  closePopup = (e) => {
    if(!e.path.includes(this.popup.current) && !e.path.includes(this.createPopup.current) || e.path.includes(this.closeX.current) || e.path.includes(this.dateSelectorHolder.current)) {
      console.log('sjasfafä');
      this.setState({
        popup: null,
        miniCalendar: null
      });

      document.body.removeEventListener('click', this.closePopup);
    };
  };

  // createEvent is used to create an new event in the calendar
  createEvent = () => {
    let elements = (
      <div className="poupContainer" >

        <div className="popup createPopup" ref={ this.popup }>
          <div className="createHeader">
            <span>Create New Event</span>
            <div ref={ this.closeX } className="closeX">&#x2573;</div>
          </div>
          <div className="createBody">
          <form onSubmit={ this.createSubmitted } >

            <span className="createLabel createTitle">
              <label>Title</label>


              <input
                type="text"
                name="title"
                value={ this.state.create.title }
                onChange={ this.createHandler }
                placeholder='Title'
                autoComplete="off"
              />
            </span>

            <span className="createLabel createTime">
              <label> Time </label>

              <span className="createTimeHolder">

                <input
                  className="startTime"
                  type="text"
                  name="startTime"
                  value={ this.state.create.startTime }
                  onChange={ this.createHandler }
                  placeholder='Start time'
                  autoComplete="off"
                />

                <input
                  className="endTime"
                  name="endTime"
                  value={ this.state.create.endTime }
                  onChange={ this.createHandler }
                  placeholder='End time'
                  autoComplete="off"
                />

              </span>
            </span>

            <span className="createLabel createDate">
              <label> Date </label>

              <span className="createDateHolder">

                <input
                  ref={this.daySelect}
                  type="text"
                  className=""
                  name="date"
                  value={ this.state.create.date }
                  onChange={ this.createHandler }
                  placeholder='DD'
                  autoComplete='off'
                />
                <p>/</p>
                <input
                  ref={this.monthSelect}
                  type="text"
                  className=""
                  name="month"
                  value={ this.state.create.month }
                  onChange={ this.createHandler }
                  placeholder='MM'
                  autoComplete='off'
                />
                <p>/</p>
                <input
                  ref={this.yearSelect}
                  type="text"
                  className=""
                  name="year"
                  value={ this.state.create.year }
                  onChange={ this.createHandler }
                  placeholder='YYYY'
                  autoComplete='off'
                />

                <span className="iconHolder" onClick={ this.dateSelector }>
                  <i className="calendar alternate outline icon"></i>
                  { this.state.miniCalendar }
                </span>

              </span>
            </span>
          </form>
          </div>
        </div>
      </div>
    );

    this.setState({
      popup: elements
    });

    setTimeout(() => {
      this.closeX.current.addEventListener('click', this.closePopup);
    }, 0);

    document.body.addEventListener('click', this.closePopup);

  };

  selected = (date, i, whatMonth) => {
    let newDate = new Date(date);
    const { create } = this.state;
    newDate.setDate(1);
    newDate.setHours(0,0,0,0);
    let toSet = {
      d: null,
      m: null,
      y: null
    }

    if(whatMonth === 'prev') {

      const prevMonth = new Date(newDate.getFullYear(), newDate.getMonth(), 0);
      prevMonth.setDate(prevMonth.getDate() - i);

      toSet = {
        d: prevMonth.getDate().toString(),
        m: (prevMonth.getMonth() + 1).toString(),
        y: prevMonth.getFullYear().toString()
      }

    }else if(whatMonth === 'current') {
      newDate.setDate(i);

      toSet = {
        d: newDate.getDate().toString(),
        m: (newDate.getMonth() + 1).toString(),
        y: newDate.getFullYear().toString()
      }

    }else if(whatMonth === 'next') {
      newDate.setMonth(newDate.getMonth() + 1);
      newDate.setDate(i);

      toSet = {
        d: newDate.getDate().toString(),
        m: (newDate.getMonth() + 1).toString(),
        y: newDate.getFullYear().toString()
      }

    }

    const day = this.daySelect.current;
    const month = this.monthSelect.current;
    const year = this.yearSelect.current;

    var nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
    var ev = new Event('input', { bubbles: true});


    nativeInputValueSetter.call(day, toSet.d);
    day.dispatchEvent(ev);

    nativeInputValueSetter.call(month, toSet.m);
    month.dispatchEvent(ev);

    nativeInputValueSetter.call(year, toSet.y);
    year.dispatchEvent(ev);

  }

  dateSelector = event => {

    //When state is updated in this function the function this.createEvent doesnt update

    let elem = {
      miniCalendar: (
        <>
          <div ref={ this.dateSelectorHolder } className="dateSelector">
            <DateSelector selected={ this.selected } />
          </div>
        </>
      )
    };

    this.setState(elem);

    setTimeout(() => {
      document.body.addEventListener('click', this.closePopup);
    }, 0);

  };


  // -- End of popup related code --

  createHandler = event => {
    const { create } = this.state;

    const name = event.target.name;
    const value = event.target.value;

    this.setState({
      create: {
        ...create,
        [name]: value
      }
    });
  };

  render() {
    return (
      <div className={ this.state.className }>
        <CalendarHeader createEvent={ this.createEvent } type={this.state.displayType.type} displayTypeHandler={ this.displayTypeHandler } resetDate={ this.resetDate } leftButton={ this.leftButton } rightButton={ this.rightButton } selectedTime={this.state.today}/>
        { this.displayType() }
        { this.state.popup }
      </div>
    );
  };
};

export default Calendar;

I removed a bunch of code from the file that is not related to my problem

标签: javascriptreactjs

解决方案


推荐阅读