Skip to content
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

use of cortex where one is not in control of renderComponent #60

Closed
braindev opened this issue Jan 13, 2015 · 6 comments
Closed

use of cortex where one is not in control of renderComponent #60

braindev opened this issue Jan 13, 2015 · 6 comments

Comments

@braindev
Copy link

This may be out of scope here but I thought I'd ask. I'm trying to react-router with cortex. One is not in control of calling render function. Is there a way of using cortex in such a fashion? The best I can come up with is a wrapper component that stores the cortex object as state and passes it down as a prop but at least one weird render problem occurs (cursor position gets lost in text fields).

Thanks

@mquan
Copy link
Owner

mquan commented Jan 14, 2015

I'm not familiar with react-router, can you provide code of what you're trying to achieve?

@braindev
Copy link
Author

A typical usage of react router might goes as follows:

var routes = (
  <Route handler={App} path="/">
    <DefaultRoute handler={Home} />
    <Route name="about" handler={About} />
    <Route name="users" handler={Users}>
      <Route name="recent-users" path="recent" handler={RecentUsers} />
      <Route name="user" path="/user/:userId" handler={User} />
      <NotFoundRoute handler={UserRouteNotFound}/>
    </Route>
    <NotFoundRoute handler={NotFound}/>
    <Redirect from="company" to="about" />
  </Route>
);

Router.run(routes, function (Handler) {
  React.render(<Handler/>, document.body);
});

You can see one is not "in control" of the React.render call. This pattern seems to be typical for other routers at well. I'm trying to use cortex and a router at the same time. What I've tried so far was to use a "wrapper" component to create the cortex object then pass it down through a prop to the "real" component.

From the example above suppose I have User and RealUser components defined like this:

var RealUser = React.createClass({ // the "real" component
  updateFoo: function(e){
    this.props.data.add(foo, e.target.value);
  },
  render: function(){
    <input type='text' value={this.props.data.foo} onChange={this.updateFoo} />
  }
});

var User = React.createClass({ // a "wrapper" component
  getInitialState: function(){
    var data = new Cortex({ foo: 'bar' });
    data.on('update', function(newData){
      this.setState({data: newData});
    });
    return {
      data: data
    }
  },
  componentWillUnmount: function(){
    this.state.data.off('update');
  },
  render: function(){
    return <RealUser data={this.state.data} />
  }
});

Everything seems to work fine except the cursor position jumps to the end of the text field on any value change. It seems wrong to store the cortex object as state in any component but I'm not sure how to do it otherwise when I'm using a router. What I'm I missing? Surely people are using a router with react and cortex (or something similar).

Thanks.

@mquan
Copy link
Owner

mquan commented Jan 15, 2015

Cortex is designed such that you can use it as either props or state, but when you use it as state then the component managing that state is in charge of changing the data. It's still unclear to me the connection between your React components and your router. Do you have Users component as well, and if so why not pass a cortex of users as props into that component?

@braindev
Copy link
Author

Here's an example of the problem I'm seeing:
https://dl.dropboxusercontent.com/u/10057662/page.zip

Try typing in the text box at the left most of the text. The cursor will jump out to the right on any modification.

type

@mquan
Copy link
Owner

mquan commented Jan 21, 2015

I think the problem is after changing the input, your handler updates the model, which triggers react to rerender and reset the cursor position

Have a look at this related issue
facebook/react#955

@mquan mquan closed this as completed Feb 23, 2015
@phred
Copy link

phred commented May 2, 2015

OK, been going back and forth on this issue for a couple of weeks now. Here's the problem:

  1. React's onChange handler triggers a re-render.
  2. Since Cortex 0.6.0, Cortex batches updates and runs them together in a setTimeout.

So the example pattern of "update state and/or props from an Cortex.on('update') callback" won't work.

Unless props and/or state are updated synchronously in onChange then the old Cortex value will get rendered again to the DOM. React triggers forceUpdate after running any onChange handlers. Because the props/state still have the old Cortex value, React will notice that domValue != reactValue and so put the old value back into the DOM, causing the cursor jump as described in facebook/react#955.

Finally, after event handling & rendering has concluded and Cortex's setTimeout gets a tick from the event loop, the components are updated and the new value is rendered to the input field.

By removing setTimeout from Cortex, things work as expected — the input updates with no cursor jumps. For now I've downgraded my project to Cortex 0.5.2.

I'm not sure what the best approach is to fixing this. I believe that forceUpdate after onChange is a relatively recent change to React, but they seem to have a good reason for doing that.

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

No branches or pull requests

3 participants