jorgebucaran / superfine

Absolutely minimal view layer for building web interfaces
https://git.io/super
MIT License
1.57k stars 78 forks source link

Skip Update/patch #147

Closed genofire closed 6 years ago

genofire commented 6 years ago

Any Idea how could i skip updating an input value when user focus it (and change it)

jorgebucaran commented 6 years ago

@genofire Do you mean something like this?

import { h, patch } from "https://unpkg.com/superfine?module"

const view = state =>
  h("div", {}, [
    h("h1", {}, state.text),
    h("div", {}, `Editable: ${state.editable}`),
    h("div", {}, `Enabled: ${state.enabled}`),
    h("input", {
      type: "text",
      value: state.text,
      disabled: !state.enabled,
      oninput: e =>
        render({ ...state, text: state.editable ? e.target.value : state.text })
    }),
    h("label", {}, [
      h("input", {
        type: "checkbox",
        oninput: e => render({ ...state, editable: e.target.checked }),
        checked: state.editable
      }),
      "Editable"
    ]),
    h("label", {}, [
      h("input", {
        type: "checkbox",
        oninput: e => render({ ...state, enabled: e.target.checked }),
        checked: state.enabled
      }),
      "Enabled"
    ])
  ])

const render = ((view, container, node) => state => {
  node = patch(node, view(state), container)
})(view, document.body)

render({ text: "Hello!", editable: true, enabled: true })

I think the relevant part is here:

oninput: e => render({ ...state, text: state.editable ? e.target.value : state.text })
genofire commented 6 years ago

nice idea, but my problem is, that the render is triggered by another event (websocket) in a view with a lot of input fields.

jorgebucaran commented 6 years ago

@genofire If you make a small demo I can have a look.

jorgebucaran commented 6 years ago

@genofire Sorry, I can't help with something of this magnitude (amount of code). I need a short, self-contained example.

genofire commented 6 years ago

try to edit the first or second input field - it will be reset if websocket / setInterval set a new values for the third input field https://codepen.io/anon/pen/MBqKNV

jorgebucaran commented 6 years ago

@genofire Thanks for the CodePen. I have a solution for you.

https://codepen.io/anon/pen/mjGqeB?editors=0010

To be able to update the state async, you need to keep track of the last state. There is no way to access the current state inside the timeout, hence the state reset.

For this example I decided to create/use a getState function (like Redux's store getState).

Then your setTimeout callback becomes:

setInterval(
  () => {
    const state = getState()
    render({
      ...state,
      list: state.list.map((item, i, { length }) => i === length - 1
        ? newRandomItem()
        : item
      )
    })
  },
  500
);

I had to make a few other changes because you were not storing the state of each input box, which you should by using oninput.

Let me know if you have any other questions.