Giter Club home page Giter Club logo

Comments (21)

dustingetz avatar dustingetz commented on August 10, 2024

@danielmiladinov @meta-meta @lijunle What do you guys think?

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

I don't fully get your meaning? How will the usage syntax look like after this change?

Will it look same as immutable.js way?

Will user need to call setState by his own code?

It could be great to provide some usage snippets.

Thanks!

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

We'd stop using React state completely, all data is above the React root and passed down as props by React.render. The Cursor constructor would be passed a reference to state value, and a setState function. Those can either be a React cmp.state and cmp.setState, or we can pass in our own reference and our own setState function that mutates the reference with updated state (no react dependency). In the non-react case, we'd have to handle re-rendering and render batching ourselves, like in ClojureScript world. I don't know how people using immutablejs handle batching but presumably its similar.

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

That is awesome. Cursor is passed from React.render function and I do not need to specially treat root component and sub-component any more.

But, AFAIK, on the React.render level, there is no way to get setState function before invoke render function.

Such syntax?

var cursor = Cursor.build(data) // no way to get setState function here
var cmp = React.render(App, cursor, dom)
cursor.initSetState(cmp.setState)

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

To directly answer your question, here is one way: https://github.com/mquan/cortex/blob/master/examples/skyline/application.jsx#L107-L113

Another way

var state = { a: { b: 42 }}; // this reference owns the state, like a singleton
var cursor = Cursor.build(state);
React.render(<App cursor={cursor}/>, domEl)
cursor.onUpdates((cursor) => React.render(<App cursor={cursor}/>, domEl))
// onUpdates needs to implement batching strategy

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

@dustingetz Your sample code is awesome!

I have two issues.

  1. How about delegate the first render inside onUpdate method and rename it to something like initUpdate
  2. React itself has already implement the batching strategy. I could prefer to leave these jobs for React and do nothing in cursor level.

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

React itself has already implement the batching strategy. I could prefer to leave these jobs for React and do nothing in cursor level.

I agree but I think this is incompatible with this approach? If I understand correctly, React batching strategy requires us use react setState. I might be wrong.

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

I search on the React source code, the answer is no.

The render function find if the element is mounted. If yes, only update the changes. Inside update function, React push the changes to the queue.

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

So if I understand correctly, this sample code will batch properly with no extra code?

cursor.onUpdates((cursor) => React.render(<App cursor={cursor}/>, domEl))

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

I think so.

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

@dustingetz I purpose the usage syntax, and update the examples and unit tests. How do you think about it? dustingetz:master...lijunle:v2

(Note: no production code changes, tests will fail.)

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

I'm still thinking about the best way to implement this. I'm currently thinking:

Two cursor types (scala syntax): ReactStateCursor(cmp: ReactComponent) and PlainCursor(value: JsObject, swapper: JsObject => ()). ReactStateCursor is just PlainCursor(cmp.state, cmp.setState). This way I can retain backwards compatibility with existing code, because one design goal of react-cursor is to be fast and easy to integrate with largish React apps that are already using React state. Then an application can derive custom Cursor types as needed, like BatchingReactCursor, BatchingPlainCursor, ReactCursorWithPendingValue (#57) etc.

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

Are you meaning that, make some inheritance with various Cursor variants?

                   PlainCursor
                   /        \
                  /          \
         ReactStateCursor   (customized) MyPlainCursor
          /           \ 
         /             \
BatchingCursor    PendingValueCursor

After that, PlainCursor and ReactStateCursor are shipped inside this package. Everybody can customize based on them.

In such case, how do you handle Cursor.build API, wrap new ReactStateCursor initialization?

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

Conceptually, yes. I would prefer composition to inheritance if possible. It's not yet clear to me the best way to handle cursor.build.

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

How about this?


From the user aspect (API aspect).

Keep Cursor.build as the current behavior for backward compatible (wrap new ReactStateCursor). This is V1 usage style.

Document and recommend the V2 usage style:

const cursor = new Cursor({ ...initial state data... }); // or use other function, i.e., Cursor.create. We can discuss
cursor.init(() => React.render(<App cursor={cursor} />, dom));

Common users only use these two APIs - V1 style for Cursor.build function, V2 style for Cursor constructor.

Internally (advanced user aspect)

Build up with inheritance as described above, but document it as advanced features.


Currently, the only one API exposed is Cursor.build function, I think such upgrade is smooth and easily understand.

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

Is v2 public api (new to construct cursor) compatible with the memoizing strategy?

from react-cursor.

lijunle avatar lijunle commented on August 10, 2024

I am not sure, but I think it can be compatible.

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

I have this working locally:

var state = {
    very: {
        deeply: {
            nested: {
                counts: _.range(400).map(function () { return 0; })
            }
        }
    }
};

function swapper(f) {
    state = f(state);
    queueRender();
}

function queueRender() {
    var cur = ReactCursor.Cursor.build(state, swapper);
    React.render(<App cursor={cur} />, document.getElementById('root'));
}

queueRender();

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

The latest api supports regular cursors (immutable value semantics for react lifecycle methods and shouldComponentUpdate) and also now RefCursors which are for business logic type code that only ever cares about the latest value and doesn't expose a notion of value equality since it is not in react lifecycle methods.

window.stateAtom = atom.createAtom({
  very: {
    deeply: {
      nested: {
        counts: _.range(400).map(function () { return 0; })
      }
    }
  }
});

function queueRender(key, ref, prevVal, curVal) {
  var cur = ReactCursor.Cursor.build(stateAtom.deref(), stateAtom.swap);
  window.app = React.render(<App cursor={cur} />, document.getElementById('root'));
}

stateAtom.addWatch('react-renderer', queueRender);
queueRender('react-renderer', stateAtom, undefined, stateAtom.deref());
var cur = ReactCursor.Cursor.build(stateAtom.deref(), stateAtom.swap)
var refcur = ReactCursor.RefCursor.build(stateAtom.deref, stateAtom.swap)


cur.refine('very', 'deeply', 'nested', 'counts', 0).value // => 0
refcur.refine('very', 'deeply', 'nested', 'counts', 0).deref() // => 0

cur.refine('very', 'deeply', 'nested', 'counts', 0).set(100)

// Regular value cursors are not changed since immutable and have value semantics
cur.refine('very', 'deeply', 'nested', 'counts', 0).value // => 0

// Reference cursors see latest value
refcur.refine('very', 'deeply', 'nested', 'counts', 0).deref() // => 100

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

(This is not merged, see #63)

from react-cursor.

dustingetz avatar dustingetz commented on August 10, 2024

Fixed in 2.0-alpha.4

from react-cursor.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.