Skip to content
This repository has been archived by the owner on Jun 11, 2024. It is now read-only.

Calendar missing headers on initial render with Preact #8

Open
jwrlee88 opened this issue Aug 13, 2018 · 22 comments
Open

Calendar missing headers on initial render with Preact #8

jwrlee88 opened this issue Aug 13, 2018 · 22 comments

Comments

@jwrlee88
Copy link

Hello,

I tried using this component with my Preact project and I noticed something odd. When the component using react-available times first renders, it renders like this image (hosted on imgur) http://i.imgur.com/u90KQhM.png

and then, when I resize the window, (e.g., I right click and open the developer console in chrome) it looks like this: http://i.imgur.com/a7Jid5U.png

I don't think it's Preact that's the issue, since Preact is just a lightweight version of React. What I've noticed is that the AvailableWidth prop gets passed down and that's what gets used to set the initial width of the headers. However, I think the problem is that the available width prop gets set to 0 upon initial load.

What is a good way I can fix this / workaround this? I would like the calendar to load fully upon initial render, and not have to have the window resized to make the headers show up.

Thank you in advance!

Here is my code to reproduce:

  1. Calendar.js
 import AvailableTimes from 'react-available-times';

class Calendar extends Component {
    render(){
        return(
                <div className="calendar">

                <AvailableTimes
                    className="calendar"
                    weekStartsOn="monday"
                    onChange={(selections) => {
                        selections.forEach(({ start, end }) => {
                            console.log('Start:', start, 'End:', end);
                        })
                    }}
                    onEventsRequested={({ calendarId, start, end, callback }) => {
                        loadMoreEvents(calendarId, start, end).then(callback);
                    }}
                    initialSelections={[
                        { start: new Date(2018, 7, 15, 8, 0), end: new Date(2018, 7, 16, 8, 0) }
                    ]}
                    height={800}
                    recurring={false}
                    availableDays={['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']}
                    availableHourRange={{ start: 7, end: 20 }}
                />
                </div>
        )
    }
}

export default Calendar;
  1. Routes.js

export default class Routes extends Component {
  render () {
    return (
      <ConnectedRouter {...this.props}>
        <div>
          <Navbar/>
          <NotificationsContainer/>
          <Switch>
            {/* Public Routes */}
            <Route path='/calendar' component={Calendar}/>
          </Switch>
        </div>
      </ConnectedRouter>
    )
  }
}```
@trotzig
Copy link
Owner

trotzig commented Aug 13, 2018

Interesting! I wonder if setting a width: 100% on the .calendar element would work? Setting the availableWidth prop is delegated to the react-with-available-width package. It will grab the initial width from the parent div (it's more complicated than that but in essence that's how it works).

@trotzig
Copy link
Owner

trotzig commented Aug 13, 2018

As you mentioned, I doubt that this is a Preact issue.

@trotzig
Copy link
Owner

trotzig commented Aug 13, 2018

Setting the availableWidth prop is delegated to the react-with-available-width package.

Scrap that! I thought I had used that package but I was wrong, this is handled in the AvailableTimes component internally. Would you mind adding some trace logs in the setRef function to figure out what availableWidth is being assigned? You can edit node_modules/react-available-times/dist/main.js directly.

@trotzig
Copy link
Owner

trotzig commented Aug 13, 2018

Also, is there a public URL I can look at the component in action myself? If not, no worries.

@jwrlee88
Copy link
Author

Thank you for getting back so quickly!

I tried setting a width: 100% to the calendar class in my css, but the same situation still happens..
I added console.log statements in the setRefs function directly.

and these screenshots are the results I get:
http://i.imgur.com/rpNGaKk.png
http://i.imgur.com/K9Ki5tE.png

the console returns 0 as the availableWidth every time...

code:

    value: function setRef(element) {
      if (!element) {
        return;
      }
      this.ref = element;
      this.setState({
        availableWidth: element.offsetWidth
      });
      console.log('the availableWidth is set to: ', this.state.availableWidth);
    }``




@jwrlee88
Copy link
Author

Apologies if that wasn't what you wanted, I wasn't sure what you meant by adding tracelogs... I also do not have a public url yet..

@trotzig
Copy link
Owner

trotzig commented Aug 13, 2018

Alright, that's what I wanted. Although you should note that this.state.availableWidth isn't guaranteed to be up to date right after a call to setState. You might be logging the previous value. Try logging element.offsetWidth instead to see what it reports.

If you try setting an explicit width to .calendar, what happens then? You could try this using inline styles:

 <div className="calendar" style={{ width: 400 }}>
   <AvailableTimes  
      ... and some props
    />
 </div>

@jwrlee88
Copy link
Author

Hello!
I tried logging element.offsetWidth and the value still remains at 0 and does not change...

I set the width using inline styles like you suggested and the headers still does not appear on initial load... Currently looks like this screenshot: http://i.imgur.com/7Rm6dIE.png

@trotzig
Copy link
Owner

trotzig commented Aug 14, 2018

Interesting. Are you doing server-side rendering by any chance? Also, if you log element.getBoundingClientRect(), what does that give you?

@jwrlee88
Copy link
Author

I am not using server-side rendering

And When I log element.getBoundingClientRect(): http://i.imgur.com/KZ1yLBt.png

@trotzig
Copy link
Owner

trotzig commented Aug 14, 2018

Is that with the inline width? I wonder what’s going on here... if you inspect the parent div in the browser, does it also show you a dimension-less element?

@jwrlee88
Copy link
Author

Correct, that is with the inline width, the parent div just has a default sizing from fitting in the child component that contains the react-available-times calendar.

I think I made some progress in finding out the issue, actually.

To investigate further since yesterday, I tried using this package on a fresh react app that I made using create-react-app, and I found that in the React project, there was nothing wrong with the package and everything worked as intended out of the box.

To investigate further, I have actually downloaded the source code and made it as a component in my Preact project, (I just had to change some module exports and imports in 3 files and put it under components/react-availble-calendar and it worked the same way). And upon digging into the source code a bit, I noticed that availableWidth is set in the setRef function within Availabletimes.jsx where state.availableWidth is set by the offsetWidth of element, which is using refs.

Preact is known for not supporting Refs out of the box, but if you have Preact-compat installed (which I do), it lets you work with string refs in preact. So I think this could be an issue with Preact and how it handles Refs.

Perhaps you could shine light on your reasoning behind the setRef(element) function? Is there a different way to find the offsetWidth and set that as the availableWidth?

Thanks for your time, I appreciate the help!

@trotzig
Copy link
Owner

trotzig commented Aug 14, 2018

I'm using setRef to grab an initial wrapper width and memoize the wrapper element. The width is then used to make rendering the calendar UI simpler. There are plenty of moving parts and they need to stay in sync. The easiest thing was to pass in the available width directly to components. There are probably ways to avoid this, but it would take quite a bit of refactoring.

You might be on to something with the React/Preact discrepancy, but from my end it looks like the setRef function is doing what it needs to, both in Preact and React.

I'm going to release version 1.2.1 that will allow you to pass in a width prop yourself. While this might not help us get to the root of the issue, it could help you work around your issue.

@trotzig
Copy link
Owner

trotzig commented Aug 14, 2018

Didn't mean to close this issue (github did it for me because I had tagged the issue in a commit).

@trotzig trotzig reopened this Aug 14, 2018
@trotzig
Copy link
Owner

trotzig commented Aug 14, 2018

Alright, if you install v1.2.1 you can pass a width prop to <AvailableTimes>. You can try passing e.g. "100%", or just a pixel number. Let's see if this changes anything.

@jwrlee88
Copy link
Author

Thanks for the new tag! However, I've been playing around with v1.2.1

and I'm sad to say the same issue still happens 😞 I can pass down the width property (either as a 100% or a pixel number value), but that just sets the width of the entire component, and does not take care of the headers not appearing on initial load.

It seemed like you got this working in Preact on your end, could I possibly see the code you did to get the package to render completely on initial load?

Thanks again!

@jwrlee88
Copy link
Author

Update:

I've found that the refs offset are always 0, so in the code when it does element.offsetWidth and sets that to availableWidth prop, the availableWidth prop is getting set to 0.

I'm seeing the same behaviour in Week.jsx with daysRef as well, where the offset of that is always returning 0, and setting available width to 0.

Perhaps as a solution we could set the width that's being passed down as a prop from AvailableTimes to the other components as well, so that we could set the availablewidth for the initial load of the calendar.

Thanks!

@trotzig
Copy link
Owner

trotzig commented Aug 15, 2018

It seemed like you got this working in Preact on your end

I haven't had time to test things in Preact. So I'm mostly just making assumptions based on what you are reporting.

Perhaps as a solution we could set the width that's being passed down as a prop from AvailableTimes to the other components as well, so that we could set the availablewidth for the initial load of the calendar.

I guess that would work, although I prefer to have one source of truth here.

In lieu of a public URL where I can test this, would you mind sharing the css involved in rendering the page? You can share as a gist if it's too long to add here in a comment.

@clucasalcantara
Copy link

clucasalcantara commented Jan 12, 2019

Hello, @jwrlee88 @trotzig! This is happening to me also :(

There is someone working on that? I'll be taking a look here because I need to fix that XD, But if anyone already has this solution 🙏

I'll continue my work to see if I can found more information.

Cya!

@clucasalcantara
Copy link

clucasalcantara commented Jan 12, 2019

update: The problem for me here is that the max-width property into the .rat-Week_header is loaded with 0px at the first render and the header component stays with the width outdated. (note, I'm using react)

update 2: Debugging the setRef function every time that the element.offsetWidthis accessed the value is 0.

screenshot 2019-01-12 at 07 49 11

inspect: screenshot 2019-01-12 at 07 49 05

@clucasalcantara
Copy link

@trotzig Another interesting fact, if you resize the window the headers work ok 🤷‍♂️

@trotzig
Copy link
Owner

trotzig commented Jan 24, 2019

Hi @clucasalcantara, sorry for the late response here. As far as I know, no one is actively working on this. I'd be very happy to merge a PR fixing this!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants