I am trying to use contextin Reactjs but I keep getting this warning from react i have tried playing with it as much as i can but nothing seems to work,
I read the post they send you too with all the comments, Didn't help much.
Followed a few online tutorials but cant seem to solve my problem, I am not sure what i am doing wrong.
the error: Warning: owner-based and parent-based contexts differ (values: `` vs ``) for key (filterItems) while mounting CategorieChooser
here is the layout basically
var Application = React.createClass({
childContextTypes: {
filterItems: React.PropTypes.array
},
getChildContext: function() {
return { filterItems: [] };
},
render: function() {
return (
<div>
<Banner />
<CategorieChooser />
</div>
);
}
});
var CategorieChooser = React.createClass({
contextTypes: {
filterItems: React.PropTypes.array
},
...
})
Related
I just started to learn ReactJS and done some tutorials. Have noticed that some write function and others do not. Some examples below. What is the difference? What should I use and when?
Render
With function
var $class$ = React.createClass({
render: function() {
return (
<div />
);
}
});
Without function
const $class$ = React.createClass({
render() {
return (
<div />
);
}
});
Update
With function
componentDidUpdate: function(prevProps, prevState) {
$END$
},
Without function
componentDidUpdate(prevProps, prevState) {
$END$
},
Default Props
With function
getDefaultProps: function() {
return {
$END$
};
},
Without function
getDefaultProps() {
return {
$END$
};
},
Those without the function keyword are the result of using the new shorter ES6 method definitions.
You can read more here: Method Definitions - JavaScript | MDN
As far as I am aware, there is no notable difference in behaviour between a shorthand definition and including the function keyword other than the former having reduced support across environments.
I have a react component that gets a prop from another parent component. I checked in react developer tools, and the prop is for sure getting passed.
Here is my code:
var Post = React.createClass({
getInitialState: function () {
return { content: this.props.content };
},
rawMarkup: function() {
var rawMarkup = marked(this.state.content, {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<div>
{this.props.content }
<div dangerouslySetInnerHTML={ this.rawMarkup() } />
</div>
);
}
});
This results in the error: Uncaught TypeError: Cannot read property 'replace' of undefined for marked.js. However, when I setInitialState to return { content: "Blah" }; it works fine. So it looks like the prop is not set there?
But when I do the {this.props.content} in the render, it works fine?
It's just that your state is out of date. Try adding this:
getInitialState: function () {
return { content: this.props.content || '' };
},
componentWillReceiveProps: function(nextProps) {
if (this.props.content !== nextProps.content) {
this.setState({
content: nextProps.content || '',
});
}
},
Read more about components' lifecycle here.
Edit: This will solve your problem, but generally using state this way is an anti-pattern (unless content is an input or something, you haven't mentioned that in your question). What you should do instead is create a new component that will only accept content prop and render marked output. I suggest you use a stateless functional component here.
var MarkedContent = (props) => {
return <div dangerouslySetInnerHTML={{__html: marked(props.content || '', {sanitize: true})}}></div>
}
Drop this component inside your Post component like this:
var Post = React.createClass({
render: function() {
return (
<div>
<MarkedContent content={this.props.content} />
</div>
);
}
});
Thanks David Walsh!
You don't have to synchronize props with state, even more using props in state is anti-pattern. render() is called each time when props or state changed
However, it's not an anti-pattern if you make it clear that
synchronization's not the goal here
var Post = React.createClass({
rawMarkup: function() {
var rawMarkup = marked(this.props.content, {sanitize: true});
return { __html: rawMarkup };
},
render: function() {
return (
<div>
{this.props.content }
<div dangerouslySetInnerHTML={ this.rawMarkup() } />
</div>
);
}
});
Do all your Post's have content?
I guess you are getting the list of posts from somewhere (a database) and for some of them the content is undefined, hence the:
Uncaught TypeError: Cannot read property 'replace' of undefined
Probably this.props.content has undefined as value. Then, this.state.content is initialized to undefined and when you call marked(this.state.content, {sanitize: true}) you get this error because you are passing an undefined to marked.
There are 3 react components, two of them inside of the first. The first component contains some state which used only in third component. When I update state from third component with callback react additionally update second component. But second component have no changes.
Why does this happen and how to avoid it?
here is my code:
var app = React.createClass({
displayName: 'app',
settingsChanged: function (value) {
console.log('app.settingsChanged');
this.setState({ settings: { value: value } });
},
getInitialState: function() {
return { settings: { value: 1 } }
},
render: function() {
return (
React.createElement('div', null,
React.createElement(component1),
React.createElement(component2, { settings: this.state.settings, settingsChanged: this.settingsChanged })
)
);
}
})
var component1 = React.createClass({
displayName: 'component1',
render: function () {
console.log('component1.render');
return (
React.createElement('div', null, 'component1')
);
}
})
var component2 = React.createClass({
displayName: 'component2',
tbValueChanged: function(e) {
this.props.settingsChanged(e.target.value);
},
render: function () {
console.log('component2.render');
return (
React.createElement('div', null,
React.createElement('div', null, 'component2'),
React.createElement('input', { value: this.props.settings.value, onChange: this.tbValueChanged })
)
);
}
})
In the console I see this:
component1.render app.js:27
component2.render app.js:42
app.settingsChanged app.js:5
component1.render app.js:27
component2.render app.js:42
http://jsfiddle.net/67m0z3ts/1/
Actually what's happening is a normal behaviour, once there is something changed in the main component, all components in that main one will be rendered again.
BUT the good news that you can change this default behaviour using shouldComponentUpdate(), which is true by default. Look at react.js documentation in advanced performance.
I hope that helps.
Good Luck
You can prevent React rendering with method shouldComponentUpdate.
So you have to add a these lines of code to your component1:
getInitialState : function(){
return {
shouldUpdate: true
}
},
shouldComponentUpdate: function(nextProps, nextState){
return nextState === this.state.shouldUpdate
},
And also Fiddle Link
I hope it will help you!
Thanks
I don't want to get into detail here, but in addition to other replies, you can try to enable the PureRenderMixin from React. From the docs:
Under the hood, the mixin implements shouldComponentUpdate, in which it compares the current props and state with the next ones and returns false if the equalities pass.
Am a little bit stuck with Meteor, Flowrouter and React when it comes to display single items. Have been trying several solutions but don't know how to transfer the ID to my React class and can't really find any information. A push in the right direction to help understand how to do this correctly would be very appreciated
My route looks like this
FlowRouter.route('/video/:_id', {
name: "video",
action(pathParams, queryParams) {
console.log("Got the postId from the URL:", pathParams._id);
console.log("Query parameters:", queryParams);
ReactLayout.render(App, {
content: <Play />
});
}
});
So this help me get the ID and then in my Play React Class i have this code
Play = React.createClass({
renderPlay() {
return Videos.findOne(FlowRouter.getParam("_id"));
},
render() {
return (
<div className="container">
{this.renderPlay()}
</div>
);
}
});
But what i really would like to do is to pass the information to my React Clip class and also put values in variables.
Clip = React.createClass({
getDefaultProps: function () {
return {
src : 'https://www.youtube.com/embed/',
width: 1600,
height: 900
}
},
propTypes: {
video: React.PropTypes.object.isRequired
},
render() {
return (
<iframe
src={this.props.src + this.props.video.videoId} frameBorder={ 0 }>
</iframe>
);
}
});
To do this i would need to include something like this in my Play class.
renderVideo() {
// Get tasks from this.data.tasks
return this.data.videos.map((video) => {
return <Clip key={video._id} video={video} />;
});
},
Would love to understand how to do this correctly and it would really be a big step in the right direction to to understand this stack.
Tutorials and guides covering Meteor + React + kadira:Flowrouter + kadira:ReactLayout that handle more than just single page apps are welcome.
I'm working with React and using React-Bootstrap components.
I found some issues in the React-Bootstrap library which I "fixed" (or "workarounded") by editing the react-bootstrap.js file. The problem is that if tomorrow a new version of react-bootstrap comes out, then I will have to copy-paste/re-write/whatever all the code I wrote in the react-bootstrap.js file to the new one. I don't want to do this, so I'm wandering if there is a way to modify the component classes (i.e. change the render function) provided by react-bootstrap without touching the react-bootstrap.js file. The problem is that I can't figure out how to do this, or at least I'm not finding easy to understand the inner working of the component classes. Any ideas on how could I accomplish this?
Thanks in advance!
You could use a wrapping component, that overrides methods of the original component after it's mounted:
function wrapComponent (originalComponent, override) {
return React.createClass({
componentDidMount: function () {
for (var property in override) {
if (override.hasOwnProperty(property)) {
this.refs.original[property] = override[property];
}
}
},
render: function () {
return this.transferPropsTo(
<originalComponent ref="original">{ this.props.children }</originalComponent>
);
}
});
}
var ConsoleSample = React.createClass({
// This method can still be used:
prefix: function (text) {
return "prefix: " + text;
},
// This method will be overridden:
output: function (text) {
console.log(this.prefix(text));
},
onClick: function () {
this.output("Hello world");
},
render: function () {
return <button onClick={this.onClick}>{ this.props.children }</button>
}
});
var Application = React.createClass({
render: function () {
var AlertSample = wrapComponent(ConsoleSample, {
output: function (text) {
alert(this.prefix(text));
}
});
return <div>
<ConsoleSample>This should console.log</ConsoleSample>
<AlertSample>This should alert</AlertSample>
</div>
}
});
React.renderComponent(<Application />, document.body.lastChild);
It's a simple hack though. I'd agree that the correct solution is to fork React-Bootstrap.