-
Notifications
You must be signed in to change notification settings - Fork 288
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SS-30102: Add react-lifecycles-compat polyfill to FDT to support v1.1… #523
Conversation
{...this.props} | ||
{...this.state} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yet another bug, the order was changed in #509, and lead to other issues.
|
||
const props = this.props; | ||
var left = props.left + this.state.displacement; | ||
static getDerivedStateFromProps(nextProps, prevState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no net change in the function, I just reordered statements to make it cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so is it just changing componentDidUpdate to getDerivedStateFromProps + reordering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. This ensures a single render after state update in response to prop change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cool. But to ensure I understand, we still get 2 rerenders, one for prop changes to the top level component, and another after the redux action is done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @pradeepnschrodinger for the detailed explanation. So if this change breaks LD is there any chance it would break other usage?
It looks from my understanding like the break comes because we're now rendering twice... once from the initial props change, and then again from the redux store updating. Is that correct? And the breaks come when logic doesn't handle possible intermediate states?
Re-rendering twice seems not great. I'm surprised React didn't propose a way to handle this case when they switched lifecycle methods up.
@@ -663,9 +663,7 @@ class FixedDataTable extends React.Component { | |||
} | |||
|
|||
componentDidUpdate(/*object*/ prevProps) { | |||
if (prevProps !== this.props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to check for change anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, because the this._didScroll
already compares the scroll props before dispatching actions.
Furthermore, I believe comparing just the prop object's reference in order to skip actions might lead to bugs in the future (like if the user just changed the classname prop but the action still fires because prop reference will get changed). So it's better if the action itself just selects and compares the props it needs.
|
||
const props = this.props; | ||
var left = props.left + this.state.displacement; | ||
static getDerivedStateFromProps(nextProps, prevState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so is it just changing componentDidUpdate to getDerivedStateFromProps + reordering?
Yep, if the library users have usages of context in their app.
Yes. To give a specific example, consider LD using FDT. When a LR is switched, the column props are changed leading to FDT being rendered. After all this, there's a second render which is triggered in response to store update through prop changes. In this render the column information matches the data in LD and should be a successful run. Sadly, FDT is unable to recover because the render tree is broken at this point, due to the previous render.
Agreed. I think a better solution would be to just use |
I take this back. It doesn't break only through context. |
Sounds good. Do you want to switch to using UNSAFE_componentWillReceiveProp? After that could you file an SS ticket for removing the use of that method w/ a better replacement and send it to me? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming we've addressed all concerns, lgtm
Whoops, there's one more issue. Instead, we can just use 'componentWillReceiveProps` for now. Is that okay? |
Ah lame. We could do that, but will still get the deprecation warning. I think that's fine though... I wonder if we could add something like.
and then use UNSAFE_componentWillReceiveProps, but still have it work on older React versions |
I couldn't figure out a neat way to detect the life cycle methods. |
Oh lame. Alright, let's go with componentWillReceiveProps & the deprecation notice for now. Could you comment on the PR / ticket which updated the lifecycle methods to ensure anyone watching that is looped in? Let's also carve out a task for a better long-term fix. |
Cool, I've ticked out SS-30193 and linked to this PR. |
Description
The master branch of FDT doesn't work in LD due to a recent release.
Breakage happens because the change affected when
FixedDataTableContainer
dispatched thePROP_CHANGE
action.Basically the redux store is updated in response to prop changes only AFTER rendering is done, because the prop change redux action is dispatched in its
componentDidUpdate
.This means, although the table gets rendered with new props, components within the tree won't get fully updated because the internal store hasn't updated yet.
Now during this time period, LD breaks!, and it has something to do with context.
The cells use data from the context, but it won't match the data in it's props, because FDT hasn't rendered them with the latest props yet (the internal store is still old).
Thus, somewhere in the cell renderer in LD, this leads to a script issue. I'll put up a CR in LD side to show/fix this.
I can't really think of a clean fix in the FDT side, unless we revert the usage of
componentWillReceiveProps
inFixedDataTableContainer
.For now, I've NOT done this in this CR as I wanted to explain and decide what approach we should go with.
I've also added the
react-lifecycles-compat
polyfill toFixedDataTableCell
.This was done because the cell component updates its state in
componentDidUpdate
. This isn't efficient since it leads to multiple renders and delayed state updates.This might also lead to problems in LD for reasons explained above; but I haven't found out if this hunch is true because because the container problem above might have masked it.
Anyway, I used
getDerivedStateFromProps
to calculate the new state, ensuring the state is updated before the corresponding render, and then added the polyfill to the component to make sure it works in older versions of React as well.How Has This Been Tested?
Tested in both LD and our examples, especially the reorder and resize column examples.
Types of changes
Checklist: