stampit-org / react-stampit Goto Github PK
View Code? Open in Web Editor NEWA specialized stampit factory for React
A specialized stampit factory for React
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')
);
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.
See react-hello for example. Should probably belong in its own repo, and just get linked to from the react-stampit docs.
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;
Is it possible to create a reference implementation of this that follows the current candidate composable spec? I think this would be a good exercise to discover weaknesses in the spec as proposed.
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.
We should come up with some webpack configs that can be used in all stampit projects.
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.
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.
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.
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?
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?
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
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:
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?
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
Utility Methods
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?
Stampit v2 has been released! Let's use here.
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
).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.