Does VueJs have the concept of Controlled and Uncontrolled Components like React? - javascript

React has the concept of controlled and uncontrolled https://reactjs.org/docs/uncontrolled-components.html components.
Where controlled are components working within the react model, and state is tracked in the virtual dom.
And uncontrolled are managed outside the virtual dom.
Since Vue also works with a virtual dom is there a wrong way to grab elements (for instance can you use document.queryBySelector or classList.add like you would if it was vanillajs to manipulate dom)?

It's not wrong to target elements with vanilla JS like you said but it's not the best practice and Vue may reject any outside attempts to mess with the DOM.
When I need to get an specific element from the DOM and manipulate it using vanilla methods I'll always do from within the Vue structure not from a separate file or script. I'd do it like this or some variation of this:
new Vue({
...,
methods:{
setClass() {
let elem1 = document.querySelector("#elem1");
elem1.classList.add("yourClass");
}
},
mounted() {
let elem2 = document.querySelector("#elem2");
}
}
If you want to add of remove classes, I would recommend you to use the Class Binding options native to Vue. And if you're dealing with forms, v-model is the way to go.

Related

How call a method from an other component

I have made an example in Codesandbox
Is there a way to collapse the sidebar by clicking on the button 'Col-2'. The button 'Col-1' is working fine, but it's necessary that is works by clicking on 'Col-2'.
I've tried to call the collapsedButton but this didn't work.
<script>
export default {
name: 'template',
methods: {
setCollapsed () {
this.collapsed = !this.collapsed
},
collapseButton () {
this.$emit('setCollapsed')
this.collapsed = !this.collapsed
}
}
}
</script>
Can someone help me out with this?
You should make collapsed a prop and control it from the parent component. You'll need to listen for the event (this.$emit('setCollapsed')) in the parent component and update collapsed accordingly.
I hope this helps, good luck!
The recommended way to achieve this is to use a store.
The store is a module, external to any component, which can be imported in any number of components. When the state of the store (which is pretty much like the data function of a component) is changed, the change is propagated in every single component where the store is used.
Since you're using Vue 2, you could use a mixin.
Here's a mixin using a basic version of a store, under the hood: https://codesandbox.io/s/vue-forked-tz1yox?file=/src/components/sidebar.vue
In more detail, it uses a reactive object which serves as shared state for sidebar's collapsed status while exposing a writable computed (collapsed) and a toggleSidebar method.
Using the mixin in any component is the equivalent of writing the writable computed and the method into the component.
Note: mixins don't play nice with TypeScript. But the above solution doesn't need a mixin. I only used one so I didn't have to write the same computed and same method in both components.
The key to it working is the shared/external reactive object. In Vue 3 you would achieve this using Composition API.

How to get Vue app container div attribute

I have a page which is being generated by my app in java (SSR) depending on some data (e.g. a publisher for some entity). I would like to create some sort of a reusable Vue component that would call an API method and request some data about the entity that is currently opened. Also in some cases there could be more than one such component on one page.
The only thing I cannot really figure out being a most-of-the-time backend developer - is how to tell a component which entity I'm trying to get. The only solution that comes to my mind is to generate the parent <div class="my-vue-component"><div> with an additional attribute, e.g. <div class="my-vue-component" publisher-id="123"><div>.
But I cannot find if there is a way to access that attribute from inside the Vue instance. (Please note that I don't have a fixed id for this div as there can be many such components on the same page referring to different data).
Any kind of advice is appreciated.
As stated in the previous answer, you will need to use props. Although since you will pass down data to multiple components and the data can change, there should be a way to respond to those changes.
For that, you will have to bind the prop with a reactive variable in your page/parent component.
So your SSR code should look like
<my-vue-component :publisher-id="openId"></blog-post>
And inside your page/parent component will reside the openId, which you can change as needed, and your component will re-render if prop passed to it changes.
export default {
data(){
return {
openId:1
}
}
}
It seems like you are looking for components-props.
You can define a prop like
Vue.component('blog-post', {
// camelCase in JavaScript
props: ['postTitle'],
Your SSR code should then be generating:
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
Inside the component methods you can access the passed in value using this.postTitle

Is it good practice to set CSS variable in the React's render method?

I have created a post yestarday and deleted it by error
I have to create a component with specific style. The problem is that the componentDidMount() method creates some king of flickering when rendering the component. It is the time that the CSS became set.
I think my component is ressource's demanding so the componentDidMount() occurs with a little frame or two of lagging. That why I am providing here just a snippet instead of a full demo, my little demo works well with zero specific flickering.
I have then entering the value in the render's method. Like the following:
componentDidMount(){
// the CSS rendering will lag by releasing a flickering :/
}
render(){
// awesome, by setting my style in the render the good style is returned instantly.
if (Math.round(window.scrollY + window.innerHeight +50) >= Math.round(document.body.scrollHeight)) {
document.documentElement.style.setProperty('--background-transition', "")
document.documentElement.style.setProperty('--is-page-bottom', "orange");
document.documentElement.style.setProperty('--background-transition', "all 0.3s ease-out")
}
else{
//setIsPageBottom_CSSVariable("rgba(84, 80, 79,0.85)")
document.documentElement.style.setProperty('--background-transition', "")
document.documentElement.style.setProperty('--is-page-bottom', "purple");
document.documentElement.style.setProperty('--background-transition', "all 0.3s ease-out")
}
Someone yesterday told me that I should use react React Hook to manage this case, or componentDidMount but componentDidMount fails in my case because of the flickering before installing the relevant background color.
I am new to React Hook so if I understand well I can make something like document.documentElement.style.setProperty in useEffect directly and it would be coherent with the design of React hook?
Meanwhile I find my solution is just good because when reading the official React's documentation, it is noted that:
The render() function should be pure, meaning that it does not modify
component state, it returns the same result each time it’s invoked,
and it does not directly interact with the browser.
If you need to interact with the browser, perform your work in
componentDidMount() or the other lifecycle methods instead. Keeping
render() pure makes components easier to think about.
Okay, if I can think about my component with a limpid manner so it is in no way a bad thing to do it isn't it? Just not the best practice I assume.
I have been advised to use an addeventlistener but here it is about instantly rendering my style on the first render component's loop. So addeventlistener is a solution for a different case that the one I am on.
In all case, which alternative would you recommend that avoid flickering when inserting my CSS setting in componentDidMount()? What is the link with the React hook?
This is how you can use useEffect
//componentDidMount replacement
useEffect(() => {
//your code goes here
}, [])
You might also consider useLayoutEffect as it fires synchronously with the DOM changes. If normal useEffect retains the issue, then you should be able to use this instead.
No, it's not good practice - you would be better off changing the class name dynamically using react, dependent on the internal state of the component.
So you could use the useState hook, and have your component in a 'loading state' which would then apply a class.
Then you could add / remove class names and associated styles using react as well, rather than inserting them with JS.
Have a look at the classNames package: https://www.npmjs.com/package/classnames
Your css would then be: .additional-class {
background: red;
}
or whatever you wanted.
Applying styles directly from React is somewhat missing the point of using react, to be honest. If you do want to do that, there are ways but should be limited, really: How to modify the DOM directly in ReactJS
https://reactjs.org/docs/refs-and-the-dom.html

Handling event using custom data attributes or binding data to the handler?

I'm using React, but this is not necessarily a React specific question.
Is there a major difference between grabbing a custom data attribute in an event handler
<MyElement greeting="hello" farewell="goodbye" />
//MyElement component
handleClick(event) {
console.log(event.currentTarget.dataset.myData);
}
...
<li data-my-data={this.props.greeting} onClick={this.handleClick}>Click Greeting</li>
<li data-my-data={this.props.farewell} onClick={this.handleClick}>Click Farewell</li>
and binding a value to the event handler
<MyElement greeting="hello" farewell="goodbye" />
//MyElement component
handleClick(myData) {
console.log(myData);
}
...
<li onClick={this.handleClick.bind(this, this.props.greeting)}>Click Greeting</li>
<li onClick={this.handleClick.bind(this, this.props.farewell)}>Click Farewell</li>
Is this just a matter of personal preference or are there actual pros and cons to each of these?
Short answer: it is a matter of personal preference AND there are Pro's and Con's to each solution.
IMHO Option 1 is a shortcut around react design principles, which can get you in a lot of trouble later on.
PRO Option 1: 'store' the data in DOM dataset:
Less tedious binding stuff in your component
dataset is also accessible from outside the react component; other components / code can directly read/ update dataset
PRO Option 2: 'store' the data in react javascript component
Less worries if the target passed is the right DOM node. (event.currentTarget takes first higher up component with event listener, event.target takes clicked element)
dataset is only accessible from inside react component, keeping your code cleaner
My personal preference is option 2: It forces you to stick to react dataflow and design principles, and keeps all relevant code in the same place, inside the javascript react component.
This safeguards you from the following route to hell (especially prevalent in larger projects and larger teams):
new requirement: some remote component needs access to dataset
the proper redesign of react component tree is tedious: you may need to move management of dataset to a higher component to give access to dataset, which means revision of react component tree.
but a shortcut is available: the remote component can also read directly from DOM - so go for the quick and dirty solution
new requirement: the original component needs an update
now there is no way of finding out which other components actually read/ rely on the dataset, so your code has in effect become unmanageable.
Do it like this, using ES6 arrow function:
<li onClick={()=>this.handleClick(this.props.greeting)}>Click Greeting</li>
This is cleaner and more efficient than bind, and requires much less code than option (1).
Only (potential) disadvantage is that in this case you create new function object every time during render(). Which will only be the problem when you're passing the callback to the custom component which is relying on shouldComponentUpdate() optimization. In this case, option (1) should work the best, as you should avoid dynamically created closures.

Find and manipulate a React.js component from the JavaScript console

When I work with JS I tend to whip out a console for the browser and manipulate values on the fly.
I have a page where I use React to render some components and I had the idea that it would be great to be able to manipulate it's state from the console to debug a design quirk which is only visible if the component is in a corner-case state.
I ran into problem that I was unable to get hold of a reference to my component.
I figured there might be a list of active components currently being rendered somewhere, but I was not able to find one on the React global object or anywhere else.
Is there an exposed reference to the components being rendered?
I'm rendering the component like:
<script>React.render(React.createElement(Comp, domElem))</script>
I could store a reference to the result of React.createElement() but it seems to be an antipattern. Also I'm using the ReactJS.NET library to handle server-side rendering for me so the whole React.render line is generated and is hard to modify.
My other idea was to create a mixin that makes the component explicitly expose itself on mount, like:
var ActiveComponents = [];
var debugMixin = {
componentDidMount: function () {
var id = this.getDOMNode().id;
ActiveComponents[id] = {
id: id,
getState: () => { return this.state; },
setState: (state) => { this.setState(state); },
comp: this
};
}
};
Are there drawbacks for an approach like this? Is this the same antipattern mentioned above?
Although being much cleaner than entangling these test hooks in the component code directly, adding a mixin is still a modification, and I would like to avoid that if possible.
The questions I hope to get answers for are bolded.
A workaround for this is to assign your object to the window object:
window.myStateObject = myStateObject
and then you can inspect it in the console:
window.myStateObject
There is a ReactJS extension for Chrome that may meet your needs https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
If that isn't good enough, React keeps track of all the mounted components in a private variable instancesByReactID. If you just want to access these for debugging, you could modify the React code and expose that variable as a global.

Categories

Resources