folks. I'm a relatively new Meteor developer, and after learning Blaze, I decided to start learning React, because it seemed like the right thing to do, and I sort of liked the idea of how it worked.
Anyway, I'm having issues with a bit of code I'm working on, and could use some guidance... I've got the following segments of code:
https://gist.github.com/czbaker/2101526219eea5330553
For some reason, when the form in the component is submitted, it isn't firing the function that's meant to handle submission. Instead, it refreshes the page (as event.preventDefault() never happens).
What would be causing this to happen? As per suggested on IRC, I've tried replacing onSubmit={this.handleSubmit} with the following:
onSubmit={()=>{this.handleSubmit}}
onSubmit={this.handleSubmit()}
Neither of them had any effect, the form submission function still isn't being called. I'm really confused, because I followed documentation for the most part, and it looks like it should be working.
As I'm really new to React, I'm sure I'm overlooking something, but have no idea what. Can anyone offer me some aid? Thanks in advance!
The current project is also in a BitBucket repository, for those who need it https://bitbucket.org/czbaker/karuto/
All I've been able to figure out so far is that if I render the problem component by itself (not as a child of another component) using ReactLayout, it works fine, but the second that I try to render it as a child component (doing it the way it's shown in MDG's Todos tutorial (React version), events refuse to fire, yet there's no errors.
Thanks in advance for help.
The problem is you are attempting to render the entire HTML tree using React.
If you are using flow-router and react-layout, you can simply render the document fragment that you desire and it will be placed in a designated root node which id is 'react-root'.
Otherwise, I would suggest using static-html if you don't need blaze and create a root element for React:
some_file.html:
<body>
<div id="react-container"></div>
</body>
and then render the root component into it using your preferred router.
Then, change the title dynamically via a ReactiveVar or some other method.
I am using React with React Router, alongside Google's MDL, and had the same issue (as well as a few others, such as navigating to different routes would cause a full page reload).
When attempting to find the cause, I found that removing the MDL classes from the the div surrounding {this.props.children} in my parent component resulted in the event listeners firing correctly.
After investigating, it appears that this is due to the way that MDL structures the DOM nodes, and can be resolved by either calling componentHandler.upgradeDOM() in each child component's componentDidUpdate() method, as follows:
App = React.createClass({
render() {
return(
<div className="mdl-layout mdl-js-layout">
...
<div className="mdl-layout__content">
{ this.props.children }
</div>
</div>
);
}
});
ChildComponent = React.createClass({
handleClick() {
alert("I've been clicked!");
},
render() {
return(
<div>
<button onClick={this.handleClick}
className="mdl-button mdl-js-button">Click Me</button>
</div>
);
},
componentDidUpdate() {
componentHandler.upgradeDOM();
},
});
As outlined here, http://quaintous.com/2015/07/09/react-components-with-mdl/; or by using a 'patched' version of MDL, like the one here:
https://github.com/tleunen/react-mdl
I know this is a little different to the OP's issue, but I figured I'd add this here in the hopes that it helps someone else with this issue. :)
In my Layout.jsx i changed
export default class extends React.Component {
render() {
return(
<body>
...some jsx
</body>
);
}
}
to
export default class extends React.Component {
render() {
return(
<div>
...some jsx
</div>
);
}
}
and it helps, now the React events are working fine
Related
I'm trying to embed a tockify calender into a component, within a react project I'm building. I should note that I'm using a library called react-script-tag that allows me to use <script/> tags within my component.
Anyway, the calender is rendering - but then keeps on re-rendering as if it's stuck in some sort of loop. I have a feeling I need to implement some sort of lifecycle method. Any suggestions? Code as follows:
import React from 'react'
import Nav from './Nav'
import ScriptTag from 'react-script-tag'
class Events extends React.Component {
render() {
return (
<div>
<Nav/>
<div data-tockify-component="calendar" data-tockify-calendar="hzevents2"></div>
<ScriptTag isHydrating={false} data-cfasync="false" data-tockify-script="embed" src="https://public.tockify.com/browser/embed.js"></ScriptTag>
</div>
)
}
}
export default Events
Use React.PureComponent instead of React.Component because of React.PureComponent will prevent to re-rendering if there is no need or update.
The documentation of 'react-script-tag' says
It is recommended that the Script tag is placed in a component that
only renders once in the entire life of your app. Otherwise, a new
tag will be appended each time the component mounts again.
There are plans down the road to prevent this.
You may want to use a pure component to prevent rerendering.
Edit: Regardless of my answer you should show the rest of your code to be able to detect the problem.
I want to implement modals within my React app. Portals seems to be quite nice for this but I don't want to change my outer HTML-structure.
The HTML-should still be:
<div id="app"></div>
I don't want to add an additional div to the HTML-structure.
In the App.js I tried to add the root-modal-container like this:
class App extends Component {
render() {
return (
<ResponsiveProvider>
<div id="root-modal"></div>
<Modal>
<div>Modal :-)</div>
</Modal>
</ResponsiveProvider>
);
}
}
But when trying to getElementById in the Modal-component I always get the error: appendChild on null...
The problem is, that the root-modal-div isn't renderend when initiating the Modal-component.
Any solutions how I can render Modals right in the level after from anywhere in my app?
You can see the not-running-code here. Uncomment the second line in HTML to get the code running.
You can do this with React portals, but it's a little awkward, and you have to get quite involved with the DOM itself to render across an app like this (rather than to totally external DOM nodes).
I've just released a library to fix this exact problem, since although it's possible with portals, it's not easy.
You can see the full details at https://github.com/httptoolkit/react-reverse-portal.
In your example, a solution would look something like:
import React from "react";
import ReactDOM from "react-dom";
import * as portals from "react-reverse-portal";
class App extends React.Component {
constructor(props) {
super(props);
// Create a portal node: the link between the two ends of the portal
this.modalNode = portals.createPortalNode();
}
render() {
// Place an OutPortal somewhere: this is where the content will appear.
// Could be many levels deep in your app - you just need to get the modalNode
// there. For complex cases you might want to put it in a context to distribute it.
return <div>
<Child modalNode={this.modalNode} />
<portals.OutPortal node={this.modalNode} />
</div>;
}
}
const Child = props => {
// Place an InPortal somewhere: this is where the content is defined
return <portals.InPortal node={props.modalNode}>
<Modal>
<div>Modal :-)</div>
</Modal>
</portals.InPortal>
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
In the above: Child defines some modal content it wants to appear, and App defines the space where modal content should appear. You can use this to link parts of your app, and send rendered content between them. Hope that helps!
I have developed a react component with three div elements like below.
render: function(){
return (
<div id="div_1">
<div id="div_2"></div>
<div>
Click the below button
Click here
</div>
</div>
);
})
In runtime, using jquery am inserting few elements into "div_2" div like below.
componentDidMount: function(){
//Invoking global function, which is outside react
window.loadView();
}
And my load view method looks somthing like below,
function loadView(){
$('#div_2').html('//my elements')
}
Now to my surprise, when I change the status of my react component, the view is getting re-rendered but somehow the contents within "div_2" remains undisturbed. Can someone say why this behaviour?
React has its own virtual copy of the DOM, hidden somewhere. React uses this to do its magic in only updating DOM when something changed from state A to state B.
In your example, React is unaware of the changes you made with jQuery to <div 2>. So, as far a React knows, <div 2> is unchanged, so React does not update it.
I would strongly advise against mixing React and jQuery for updates to components. If you want to keep your code manageable, give React the exclusive monopoly to update the DOM.
In your case, I would advise to let React only manage the inner part, like so:
render: function(){
return (
<div>
Click the below button
Click here
</div>
);
})
And in your HTML:
<div id="div_1">
<div id="div_2"></div>
<div id="react-only domain"></div> // mount your ReactDOM here
</div>
You should use componentDidUpdate in your case instead of componentDidMount.
Recently I started to refactor my Backbone web app with React and I'm trying to write interactive graph visualization component using react and sigma.js.
I roughly understood React's declarative paradigm and how it is implemented by render() method using jsx syntax.
But what gets me stumbled is a situation where I cannot define my React component declarativly.
It is because of the javascript-generated DOM elements, which only can be generated on componentDidMount() after the declarative DOM elements are rendered by render().
It makes me worried about both performance and buggy animations (my graph animates on instantiation time, which will be re-played on every render() calls in this situation)
My current code looks like:
...
render: function() {
return (
<div class="my-graph-visualization-component">
{/*
This div is defined declaratively, so won't be re-rendered
on every `change` events* unless `React`'s diff algorithm
think it needs to be re-rendered.
*/}
<div class="my-declarative-div">{this.props.text}</div>
{/*
This div will be filled by javascript after the `render()`
call. So it will be always cleared and re-rendered on every
`change` events.
*/}
<div class="graph-container MY-PROBLEM-DIV"></div>
</div>
);
},
componentDidMount: function() {
this.props.sigmaInstance.render('.graph-container', this.props.graph);
}
...
Is there any way to do something like
render: function() {
return (
<div class="my-graph-visualization-component">
<div class="my-declarative-div">{this.props.text}</div>
{/*
Any nice workaround to tell react not to re-render specific
DOM elements?
*/}
<div class="graph-container NO-RE-RENDER"></div>
</div>
);
},
so that my sigma.js graph component won't get re-instantiated with identical starting animation on every change on states?
Since it seems to be it is about handling non-declarative part of react components, any workarounds for this kind of problem will be appreciated.
The cleanest way is to define react sub-components and re-render what you really need instead of re-rendering the whole block
render: function() {
return (
<div class='myStaticContainerNotupdated'>
<SubComponentToUpdateOften/>
<MyGraph/>
</div>
)
}
The other solution could be to work on your graph and implement a singleton so your animation is only played once at the first render.
But really the easiest and cleanest thing I see is to create clean separate subcomponent and update them when needed. You never update the big container component just the subs one.
Hope it helps
You can use dangerouslySetInnerHTML. This basically tells React to stay away from it’s content and it wont evaluate/update it when doing it’s DOM diffing.
I've been experimenting with creating a component based UI using ReactJS, versus my usual slapdash approach of a million global functions, variables and non-reusable markup. So far I really like React but I've hit a stumbling block.
Consider the following component layout
EventView
EventViewSidebar
EventViewList
EventViewListRow
EventViewDetail
In this layout, multiple occurrences of EventViewListRow are present for each unique key. Clicking an instance of EventViewListRow should update EventViewDetail with the details of that item.
This is the render function for the top level EventView component:
render: function () {
return (
<div className="event-view row-fluid">
<div className="event-view__sidebar col-md-4">
<EventViewSidebar projectId={this.state.projectId} />
</div>
<div className="event-view__content col-md-8" id="eventDetail">
</div>
</div>
);
}
And this is the EventViewDetail component
var EventViewDetail = React.createClass({
getInitialState: function () {
return { eventId: 0 };
},
render: function () {
if (this.state.eventId === 0) {
return (<h3>Nothing selected</h3>);
}
else {
return (
<div>
{this.state.eventId}
</div>
);
}
}
});
For the updating of EventViewDetail when a EventViewListRow is clicked, I have the following event handler defined in EventViewListRow
handleClick: function (event) {
event.preventDefault();
React.render(
React.createElement(EventViewDetail, { eventId: this.props.id }),
document.getElementById("eventDetail")
).setState({ eventId: this.props.id });
},
This all seems to be working fine (with the exception of the setState call above which I had to add otherwise clicking a different EventViewListRow didn't seem to have any effect - no doubt that's my first problem). The actual critical problem is that if I add default html to the eventDetail div defined in EventView then when I click the link in EventViewListRow, the following message is displayed in the console and the browser hangs.
Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) <h3 data-reactid=".0">Nothing selected
(server) <h3 data-reactid=".0.1.0">Select an even
Once the browser tab (Chrome 43) has hung, I have to terminate it using Task Manager.
Originally, I was calling an instance of the EventViewDetail directly, for example
<div className="event-view__content col-md-8" id="eventDetail">
<EventViewDetail />
</div>
but it also hangs if I just use vanilla HTML
<div className="event-view__content col-md-8" id="eventDetail">
<h3>Select an event to view</h3>
</div>
Clearly I'm doing something very wrong, but I'm somewhat unfamiliar with React so I don't know what that is. I read that I'm suppose to have state on the top level EventView component, but I don't have access to that and React doesn't seem to offer the ability to go back up the component chain. Unless you are supposed to pass the EventView instance as a property to each child component?
Oh, I should also add - I also tried removing the setState call from the EventViewListRow click handler in case that was the cause, but it had no effect.
Can anyone offer any advice on what it is I'm doing wrong. Should EventView have all the state for the child components, and if so, how do I reference the parent from a nested child component - do I have to pass the instance of EventView as a prop to every single child?
Sorry if these are idiot questions!
You should not call React.render in the handleClick function. Just call this.setState and React will automatically render again.