React component ignores dynamic element while re-rendering - javascript

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.

Related

DOM remove method in react js

I want to change remove a certain tag with an id in the html page, eg.<div id="theid"><p>sometext</p></div> Is there any ways to do it with react js? I know I can do it with javascript by document.getElementById("theid").remove();, how can I do it in the react way? I don't need a button or anything, just simply remove it when the page loads. I'd prefer methods without importing any modules or libraries if possible. Thank you.
You should likely use a ref:
https://reactjs.org/docs/refs-and-the-dom.html
So you attach the ref to the DOM element, then you can imperatively remove that element just like you specified.
So in the component function body:
const myRef = useRef();
Then in the component render:
<Component ref={myRef} />
Then you can use the code in your question to remove the element from the DOM.
ref.remove();
If you need to do it when the page loads look at using useEffect to achieve this. Although if you're removing an element on page load, I question why you even need the element there in the first place ;).
If it's rendered as part of React, the right way to do it would be to simply omit it from the source code:
const App = () => (
<div>
<div id="theid">foo</div>
<div>more content</div>
</div>
);
to
const App = () => (
<div>
<div>more content</div>
</div>
);
If it's not part of React, then remove it from whatever process generates the HTML.
If that's not an option - if it must be part of the HTML served to the client and it's not rendered as part of React - then you'll have to resort to doing what you're currently doing:
document.getElementById("theid").remove();
probably completely separate from your React script, since it's something you want to do only once, when the page loads, and not something that needs to be a part of the React lifecycles.

Having trouble building a simple audio player in React using HTML5

I've recently started learning React and I'm trying to build a simple audio player. I'm currently using this example as a reference but it's built in one file
https://github.com/CezarLuiz0/react-cl-audio-player
The one I'm trying to make is done in a "React" way where the UI has reusable components but I'm having trouble separating my code into meaningful and working components. For example, if I try to move some of the rendering code from the parent component (AudioPlayer) into (PlayButton), the audio methods that is created on the mounting of the parent component suddenly becomes inaccessible to the child components.
Here is my code repo.
https://github.com/vincentchin/reactmusicplayer
It works now but I'd like to improve it. Also it'd be great if someone can point out huge flaws in this since I'm sure I've broken some rules or standards to coding in React.
You can access parent component's methods from a child component by passing the method as a prop, and then invoking it inside the child component.
For example (in the child component's render method):
<button onClick={this.props.methodFromTheParent}>Click me</button>
You can also pass arguments to these methods:
<button onClick={this.props.methodFromTheParent.bind(null, 'Hello')}>Click me</button>
Remember to pass in null instead of this as the first argument when binding values to a method belonging to a parent component.
I skimmed through your repo as well. You could clean up the AudioPlayer component a lot by putting the different elements into their own components.
The render method could look something like this:
render() {
return (
<div>
<PlayButton onClick={this.togglePlay} playing={this.state.playing} />
{!this.state.hidePlayer ?
(<Player
playerState={this.state}
togglePlay={this.togglePlay}
setProgress={this.setProgress}
...
/>) : null}
</div>
);
}
And then inside the newly-created Player component:
render() {
var pState = this.props.playerState; // Just to make this more readable
return (
<div className="player">
<PlayButton onClick={this.props.togglePlay} playing={pState.playing} />
<Timeline
currentTimeDisplay={pState.currentTimeDisplay}
setProgress={this.props.setProgress}
progress={pState.progress}
...
/>
<VolumeContainer
onMouseLeave={this.props.noShow}
setVolume={this.setVolume}
toggleMute={this.toggleMute}
...
/>
</div>
);
}
You can break the layout into as many nested components as is needed and makes sense.
Remember to actually add the onClick attribute inside the child components as well (<button onClick={this.props.onClick}>Play</button>).

Child Component in React (Meteor) not firing events

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

How to not re-render React component's specific DOM elements?

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.

Re-rendering a ReactJS component hangs browser

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.

Categories

Resources