Giter VIP home page Giter VIP logo

react-stampit's People

Contributors

ericelliott avatar fredyc avatar josephclay avatar troutowicz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

joshdmiller

react-stampit's Issues

"this" undefined

Hi, I am trying to use the library to make an isomorphic application. I have a component like this:

const CreateComponent = stampit(React, {
  state: {
    text: 'something'
  },

  changeState: function(event) {
    console.log(this.state.text);
  },

  render: function() {
    return (
      <input type='button' defaultValue={this.state.text} onClick={this.changeState} />
    );
  }
});

It renders, both server and client side, but when I click on it I receive this error Uncaught TypeError: Cannot read property 'state' of undefined.

I am rendering server-side like this

var CreateComponent = React.createFactory(require('../app/components/CreateComponent.jsx'));
router.get('/component/create/', function (req, res, next) {

  let createComponentReact = React.renderToString(CreateComponent({}));
  res.render('admin/createComponent',
    { title: 'Title',
      createComponentReact: createComponentReact });
});

And client-side like this

var CreateComponent = require('./components/CreateComponent.jsx');

React.render(
  <CreateComponent />,
  document.getElementById('CreateComponent')
);

Converting existing ES6 React Components to stamps

import stamp from 'react-stampit/lib/utils/decorator';

class Component extends React.Component {

    render(){
        return (<div />)
    }
}

export default stamp(Component)

Is something like this possible? I'd like to convert my classes to stamps centrally without using decorators.

Components can't safely import React

I just noticed a pretty serious flaw in react-stampit:

Component source files should never import React, because that could lead to multiple instances and multiple versions of React in the same project -- a situation that causes bugs. Instead, it should be passed into the stamp when an instance is instantiated (dependency injection). You'll need to work some magic to expose the React.PropTypes for the react-stamp to use.

A fix for this issue will be a breaking change, and any users who've managed to find this already should upgrade immediately to the fixed version to prevent bugs in their applications.

Example from react-hello:

import React from 'react'; // we can't do this...
import stampit from 'react-stampit';

const {
  string,
  func
} = React.PropTypes;

Why strip stamps?

Hello All!

I recently became a convert from es6 classes to stamps and loving every minute of it. Just converted a project of mine that had a bunch of es6 classes into stamps. It helped clean up my api in a great way!

I have a related project that uses es6 React class and I wanted to give this project a try. One component needs childContext working so react-stampit was not useable there, but createClass worked fine for that. The other has a lot of logic going on in the constructor method which I thought would work out fine as I can just use the stampit init method for that. Turns out all the beloved stampit methods are stripped from the factory.

What was the reasoning here? It seems to deflate the awesomeness that is the stamp.

Lets use webpack

We should come up with some webpack configs that can be used in all stampit projects.

Component/Mixin functions not bound to component scope

Main Issue
When using React-Stampit with Cerebral, I get the error:
Cannot read property 'cerebral' of undefined
(Error is on line 39 of cerebral/src/mixin.js)

Stack Trace

mixin._mergeInState @ mixin.js:39
EventEmitter.emit @ events.js:99
(anonymous function) @ createSignalMethod.js:169
(anonymous function) @ createSignalMethod.js:165
signalPath.path.(anonymous function).runSignal @ createSignalMethod.js:181

This is due to the this keyword referencing Cerebral and not the component.

After debugging this I found that React auto-binds the component scope for components/mixins, so the "this" keyword references the component.

Example code can be found here. Here's my react stamp, and then the main app file.

Secondary Issue
A related issue, is events in component markup require being wrapped in a function in components because they too are lacking the component scope. They do not need to be wrapped when using React.createClass.

Example:

export default React => stampit(React, {
    ...
    onBtnPress() {
        this.signals.addTodo();
    },
    render() {
        ...
        return (
            ...
            <button onClick={ () => this.onBtnPress() }>Press Me</button>
            ...
        );
    }
})
.compose(mixin);

Where changing the onClick attribute on <button /> will affect the reference of this in onBtnPress.

    onClick={ this.onBtnPress } // In onBtnPress: this = Window
    onClick={ () => this.onBtnPress() } // In onBtnPress: this = Component

When using React.createClass, no wrapping is needed.

Findings
I tried finding a fix for this myself, but I'm having trouble finding where the instance of my component is being held/created. In react-stampit compose function, I only have access to the factory. Haven't been able to get passed this point yet, but will keep trying. (Maybe someone can help point me in the right direction.)

I believe this can be fixed by using .bind(componentInstance) on each component method. I've been able to hack the compose function so that it does bind something, however it's not the component instance, so no dice.

It looks like React has an autobinding feature which is used in the function mixSpecIntoComponent in ReactClass.js.

if (shouldAutoBind) {
    if (!proto.__reactAutoBindMap) {
        proto.__reactAutoBindMap = {};
    }
    proto.__reactAutoBindMap[name] = property;
    proto[name] = property;
} else {
    ...
}

I don't know what any of the variables involved in this code block really are. Below is based off of what I've observed:

proto is ReactClass.createClass.Constructor
name is getDOMNode or trapBubbledEvent
property is a Mixin (ReactBrowserComponentMixin or LocalEventTrapMixin)

I can only guess how to fit this into React-Stampit at the moment. I will try accessing the constructor via Factory.constructor, and go from there.

Compose does not work as expected (caching)

Adding react-routers navigation mixin to a component. The component has displayName 'lecture'. The mixin has no displayName, as it is a mixin. As per examples in README, I expected this to work fine. See: https://github.com/stampit-org/react-stampit#what-is-this

At first I was annoyed that my mixins had to have displayNames in order to actually get mixed in. I see now that the API does state it expects stamps, not just mixins. This just means that the README examples need to be updated to actually create stamps with displayNames not just throw in plain mixins (mixins as created for the react community).

But then I noticed something odd. The displayName used to get from cache is the displayName of the last stamp in the stamps array in the compose method. The last stamp is the context of the compose function. This means if I use the compose method with a stamp created with a property 'displayName', the stamp I am calling compose from will be used to check and get from cache. If I'm looking at this right, the compose method will never work as expected when the context has a 'displayName' property.

Looking through tests/compose I see displayName is never used in test. I also see that you do test using POJO and that was intended to be used with plain react mixins.

A Proposal: Remove Stamp Caching

Caching of stamps is something that should be done in user land, and right before handing of to React. I think this issue is a good example of why not to cache internally. If I hadn't dived into the source I wouldn't have known that stamps where being cached. In fact the word cache is not used anywhere in the README. And only comes up in one PR.

Cerebral stamp

I'm thinking of using Cerebral for my next app. It seems like it would be easy to create a Cerebral component stamp that could augment any container component by composing it in.

Thoughts?

Composing Refs

Hello! I'm trying to create a mixin that components that need to connect to a Flux-like store can use, but I'm confused between stampit and react-stampit lands. I would expect the following (truncated) code to work, but this.stores is undefined at the comment below:

import React from 'react';
import stampit from 'stampit';
import rStampit from 'react-stampit';

// the mixin
var StoreConnector = stampit({
  refs: {
    stores: []
  },

  methods: {
    componentWillMount () {
      // this.stores is undefined, though it's defined above and in the other stamp
      this.stores.forEach( store => /* ... */ );
    }
  },

  init: function () {
    // Results only in `{ state: {} }`
    console.log( 'this', this );
    this.state = this.getState();
  }
});

// the component
var Component = rStampit( React, {
  stores: [ store ],

  getState () {
    return {
      name: store.getValue()
    };
  },

  render () {
    // This works because `getState` is called by the mixin's `init`, as expected.
    return (<div>The name is <b>{this.state.name}</b></div>);
  }
}).compose( StoreConnector );

I am having difficulty mixing in any refs, it would seem. Am I approaching this incorrectly? Would it be better to just use stampit?

react-stampit with material-ui

I'm trying to implement react-stampit with material-ui
To set material-ui I need to set getChildContext() and childContextTypes.

for some reason when trying to so I get an error:

uncaught Error: Invariant Violation: ReactStamp.getChildContext(): childContextTypes must be defined in order to use getChildContext().

here is the code i'm running

import stampit from 'react-stampit';
import { Styles, RaisedButton } from 'material-ui';

const ThemeManager = new Styles.ThemeManager();


export default React => stampit(React, {
  childContextTypes: {
    muiTheme: React.PropTypes.object,
  },
  getChildContext() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  },
  render() {
    return <div>
        <h1>Hello World</h1>
        <RaisedButton label="Click Me" />
      </div>
  }
});

Any idea what i'm doing wrong?

Thanks

Not working with Radium

I'm a big fan of what react-stampit represents in terms of application structure, and I began to use it in a project recently to become more familiar with React. Another thing I found exciting about React was the possibility of proper scoping for styles, especially with the extra features of a library like Radium.

Unfortunately when trying something similar to the following code, I found that components created through react-stampit factories weren't working when they are wrapped in Radium().

import React from 'react';
import Radium from 'radium';
import component from 'react-stampit';

const mount = document.querySelector('.mount'),
    style = {backgroundColor: '#36d'},
    appFactory = React => component(React, {
        render() {
            return <h1 style={style}>Heya</h1>;
        }
    }),
    App = Radium(appFactory(React));

React.render(<App />, mount);

This throws the following exception on render:

image

From sorting through the source code a bit, the problem seems to stem from Radium checking the prototype of the component, and the prototype resolving to Factory instead of what Radium expects.

Is there some general guidance for using react-stampit components with Radium or is it an incompatibility between the two APIs?

API

Let's discuss what the final API should look like. Do we want to include any of stampit's utility methods?

Public Stamp Interface
- [ ] stamp.methods
- [ ] stamp.state
- [ ] stamp.enclose

  • stamp.compose

Utility Methods

  • stampit.compose
  • stampit.isStamp

Simplify README

We should move the API documentation into a seperate file in docs/.

On a different but related note, I think the isStamp static utility method should be removed and just made available as a utility. This will move us closer to conforming to the future standard stamp spec.

import { isStamp } from 'react-stampit/utils';

Maybe another file should be made in docs/ for mentioning available utilities?

Strip state prop in favor of init?

It has been mentioned a few times now how an init method prop in the description object would be useful. See issues #21, #29. What if the API was changed, removing the state prop of the description object and in it's place have more flexible init method prop?

init would behave just as init behaves in the core stampit library, so component state would be set like:

stampit(React, {
  init() {
    this.state = { ... }
  }
});

instead of

stampit(React, {
  state: { ... }
});

This is more typing for declaring component state, but the init method would allow a wide range of use cases currently not possible. It also makes sense to have a constructor like method at the stamp level (init) as well as the React level (componentWillMount).

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.