Change an element using ref (third-party library) - javascript

I use a third party library to display a table with pager :
<Grid
ref={Grid => {
this.gridRef = Grid;
}}
{...props} />
I want to modify only the pager and create a new class GridPager to override it.
In my componentDidMount I can display the element of my Grid :
componentDidMount() {
// display the Grid elements
//console.log(this.gridRef.widgetInstance.element);
// This won't work
//this.gridRef.widgetInstance.element[0].childNodes[1] = <GridPager />;
// Change the Grid pager to simple 'test'
// this.gridRef.widgetInstance.element[0].childNodes[1].innerHTML = 'test';
}
I can add simple text using innerHTML but how to add a React class GridPager ?
This is my first time I use ref and working on DOM using React.

By what I can tell what you are trying / want to do is both not possible or discouraged.
There should be no way of actively modify the React DOM like that.
childNodes elements should be read only even if you can still modify the inner HTML.
refs should be used to trigger events across different Components of the React DOM when for some reason you don't want to use the props for passing funcions.
See more here https://reactjs.org/docs/refs-and-the-dom.html#dont-overuse-refs
and here https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components
I see what and why you are trying to do this, but if you are using a component that you didn't create I don't think it's a good idea to try to modify it on the code that wraps or uses it and would instead make changes directly from the source.

Related

I get a style list with empty values when call element.style (React)

I want to get the height of an element, and the width of Body, so I called
document.style.width
[element].style.height
That returned empty strings, so I got When I call [element].style / document.style I receive this:
CSS list
Why does this happen? ¿Is an issue of React? I'm not using styled components, only css templates with css-loader and style-loader of webpack
You need to think it like a react, here in your sample, you are do that via real dom, and its incorrect, what you need to do, its use useRef
For example:
const imageRef = useRef(null);
<img
ref={(node) => {
imageRef.current = node;
}}
/>
and you can use it like this (like real dom):
imageRef.current.clientHeight
You can read this topic: React Ref and Dom
Probably this is because nowhere as yet in the code have the styles been set (in the sense of element.style.property = value for example in JS, or style="property: value;" inline in the element).
I suspect that the styling is being done through stylesheets and classes.
What you want is to get the current computed stle. Try:
window.getComputedStyle(element);
on the elements you are interested in.
See https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle

Using querySelectors with useEffect in React to modify HTML elements

I'm trying to add a class on load to an HTML element which is going to be rendered with a functional component in React. When I try to do this with useEffect() it doesn't work since the function runs before I can have access to the element and returns undefined. I've been researching this a whole lot and still can't find a solution. I'm trying something like this:
function myComponent() {
useEffect(() => {
const el = document.querySelectorAll(".item");
const firstEl = el[0];
const lastEl = el[el.length -1];
firstEl.classList.add("red"); // Add class to the first element with class .item
lastEl.classList.add("blue"); // Add class to the last element with class .item
}, [])
return (
<div> // We don't know how many items there are going to be, for simplicity here are three span's
<span className="item">1</span>
<span className="item">2</span>
<span className="item">3</span>
</div>
);
}
This would be fairly easy in plain HTML and javascript, but I'm having difficulties making the code inside useEffect() have access to the elements in the component.
PD: For simplicity, I'm setting the items as three <span>'s, but in reality the items are conditionally rendered and I do not know how many of them are they going to be. Also, I'm aware that you could achieve something similar using css child selectors, and I wish I could use them, the example I gave is just a simplification of the code to make the problem easier to understand, but in my specific case, I need to use javascript selectors and I also need a way to do it in ReactJS.
As I understood, your question is a simplified form of the situation.
You probably have an array of items and you are going to render them.
There is no need to select the first and last item in this way. you can simply filter the valid items for render, then map through them, finally add the proper className to the elements you want. you can find the first and last elements by checking their index inside the map.

Vue.js equivalent of appendChild to dynamically add new element/component?

In Vue.js, I have a var app = new Vue({...}); and I have a component Vue.component('mycomponent', ... where I can use such component without any issue by directly adding <mycomponent></mycomponent> in html. What I wish to do is to dynamically add those component on demand maybe after a button click or when some other such event takes place. In raw JS, I'd use document.createElement... when event fires and then do el.appendChild.. to add it into html. How would I do the same with Vue.js ?
I'm not doing anything fancy with node js. This is on a single html page with <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> in the <head>.
To do this the "Vue way" usually involves the use of v-if, v-for or <component>, depending on what you want to do:
Use v-if to conditionally show a component/element based on a condition.
Use v-for to render a list of components/elements.
Use <component> to render a dynamic component/element.
So to achieve what you described in your question, you can declare a boolean data property visible like this:
data() {
return {
visible: false
}
}
and use it with v-if to control the visibility of a component in the template:
<mycomponent v-if="visible"></mycomponent>
This requires that <mycomponent> exist in the template upfront. If you don't know what kind of component you want to show, then you can either include each possibility in the template and display the one you want based on some condition:
<comp1 v-if="comp1Visible"></comp1>
<comp2 v-if="comp2Visible"></comp2>
<comp3 v-if="comp3Visible"></comp3>
or you can use <component> together with another data property (comp) which you can set to the name of the component you want to display:
<component v-if="visible" :is="comp"></component>
What you described (document.createElement followed by el.appendChild) does not exist in Vue. Vue has a strict rendering mechanism which you need to work with; it isn't possible to dynamically instantiate components and stick them into the DOM randomly. Technically you can do comp = new Vue() as an equivalent to document.createElement and then el.appendChild(comp.$el), but that probably isn't what you want to do because you would be creating an independent Vue instance that you would have to manage manually with no easy way of passing data around.

How to select a React Component by ID="" in React (without using ref)

I am importing SVG elements into React component, and then rendering them as components.
How do I attach a reference to React Components that contain SVG elements from within my componentDidMount()?
Well, i don't see code example. U can try to use jQuery, when your component render will finish - this is magic stick in many situations. Just type smth like:
let element = $('#element_id');
And you will get access to its information

Render Normal JavaScript in React

So I'm new to react and I'm trying to understand how non-react code and react code can interact.
So for example, let's say I have a library which draws a circle in a DOM element with syntax like this:
c = new Circle('#container')
and as soon as that code is executed, a circle is drawn in the DOM element with an id of container.
If I wanted to create a React component based off of this, how would I go about it? This is what I had in mind:
var circ = React.createClass({
componentDidMount: function(){
c = new Circle('#container')
},
render: function(){
return (
<div id="container"></div>
);
}
});
Is this acceptable, or is there a better way to go about this?
For example if you want to interact with DOM, you can add special ref prop to some element like:
<div ref="blabla"></div>
and interact using regular javascript api, or other non-react apis.
ReactDOM.findDOMNode(this.refs["blabla"]).style.display='none'
Here I'm hiding element with ref "blabla"
Yes, your approach is right, but there are few moments you need to keep in mind.
React can rerender it's DOM and bindings of Circle library can be broken. So use shouldComponentUpdate() to control render process. https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate
Don't forget to unbind Circle library on component destroying.
https://facebook.github.io/react/docs/react-component.html#componentwillunmount
If I understand it right, the Circle() will print out a element inside the DOM element you provide as a parameter.
If it was me I would have a diferent approach on that. Instead of using that component to manage/edit the DOM element, use the result result of it to be printed inside the DOM element. So, if the Circle() returns a SVG code grab it and print it out inside the #container. If it is a script to generate a base64 image, get the result to print inside #.
I would avoid to use react as a DOM manager, as you can do with jQuery, instead try to think react as a blocks/components manager, so you replace a component with another.

Categories

Resources