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

Hot reload #73

Merged
merged 22 commits into from
Nov 14, 2018
Merged

Hot reload #73

merged 22 commits into from
Nov 14, 2018

Conversation

T4rk1n
Copy link
Contributor

@T4rk1n T4rk1n commented Aug 31, 2018

Available with the following version:

  • dash==0.27.0rc7
  • dash-renderer==0.14.0rc6

Add hot-reload capability on project file changes by periodically requesting a hash and checking it's the same hash as the initial one.

Adds:

  • Reloader component
  • reloadRequest api thunk.

Need plotly/dash#362

@T4rk1n
Copy link
Contributor Author

T4rk1n commented Sep 11, 2018

@plotly/dash Ready for review!

Copy link
Contributor

@rmarren1 rmarren1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! There's two questions I had, and two newlines missing

}),
dispatch => ({dispatch})
)(Reloader);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline

src/actions/api.js Outdated Show resolved Hide resolved
if (!disabled && !this._intervalId) {
this._intervalId = setInterval(() => {
if (!this.state.reloading) {
dispatch(getReloadHash());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should state.reloading be set to true here? I do not see anywhere that state.reloading is changed, it seems to always be false.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a leftover from something I tried, I will remove thanks.

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I there extra stuff in state that is stripped when you do this? I don't see what these two lines do, I don't think state is changed here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything but the history is stripped down, it triggers a soft reload.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh okay so everything else gets set to default except the history, looks good

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

Copy link
Contributor

@valentijnnieman valentijnnieman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left you a couple of questions!

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you not combine this reducer into the recordHistory function that's already there? I'm not sure I understand why it is a separate reducer.

}
if (reloadHash.content.reloadHash !== this.state.hash) {
// eslint-disable-next-line no-undef
window.clearInterval(this._intervalId);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the no-undef rule here should not trigger if it's sure that this._intervalId is set, right? Maybe it's better to write a check here that makes sure that it's not null, instead of disabling the rule.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The no-undef is for window, it highlight as error in pycharm.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rootReducer is for soft-reload, it destroy the state of the store and then the other reducers can reload the application. I think it's cleaner to keep it separate as the logic for the historyReducer come after and they do different operations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok! Hmm maybe that rule can be turned off globally then, if it's always going to trigger on window?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last question: isn't it maybe better to put the rootReducer in a separate file, and call it something else, like reloadReducer or whatever?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe that rule can be turned off globally then

I think we can put window in a global exclude or something. Anyway it underline as error in IDE, I just hit alt-enter and select a fix, doesn't take more than a second.

Last question: isn't it maybe better to put the rootReducer in a separate file

It's only a couple lines and is the last reducer exported, keeping it in reducer make more sense to me.

if (reloadHash.content.hard) {
// Assets file have changed, need to reload them.
// eslint-disable-next-line no-undef
window.top.location.reload();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, why is the no-undef rule triggering here?

@@ -20,6 +20,7 @@ const reducer = combineReducers({
dependenciesRequest: API.dependenciesRequest,
layoutRequest: API.layoutRequest,
loginRequest: API.loginRequest,
reloadHash: API.reloadRequest,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason why it's named reloadHash here and reloadRequest on API.reloadRequest?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, I refactored reloadHash to reloadRequest to conform to the other API, I guess that one didn't follow up.

disabled: true
}
}
this._intervalId = null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can _intervalId not be in state as well?

hash: null,
interval,
disabled: false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if this state is also handled in a reducer? Would there be value in having this state in the store? Perhaps saving the hash in the store for example would make it easier to at some point in the future to enable the store to be saved client-side, so that it can be rehydrated upon refreshing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hash is null at first, it is set in the state from the server on the first hash request so I don't think it needs to be rehydrated.

Copy link
Contributor

@rmarren1 rmarren1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor style changes 💃

@@ -19,3 +19,4 @@ simple*

*.csv
.idea/
.vscode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

disabled: false,
intervalId: null,
packages: null,
max_retry: max_retry,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just max_retry

);
let node = it.iterateNext();

while (node) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is node a proper iterator? You should be able to do const nodesToDisable = [...it.iterateNext()]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a proper iterator but it doesn't work, if there's no element found (asset file added) it will fail to make an array with the iterator.

nodesToDisable.push(node);
node = it.iterateNext();
}
nodesToDisable.forEach(n =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are trying to use ramda 🐏 in this repo even when a core library function would do the job. I think R.forEach would do the job.

} else if (reloadRequest.status === 500) {
if (this._retry > this.state.max_retry) {
window.clearInterval(this.state.intervalId);
// Integrate with dev tools ui?!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🐱

function rootReducer(reducer) {
return function(state, action) {
if (action.type === 'RELOAD') {
const {history} = state;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be separate from recordHistory. This reducer doesn't really change the history, it just removes everything else. It could have a different name though for sake of clarity, maybe like preserveHistoryOnReload

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

Successfully merging this pull request may close these issues.

None yet

3 participants