CSS styles not being applied to HTML within a Vue Component - javascript

I am trying to create a rotating text animation using Vue.js and I used this CodePen as inspiration.
I got all the HMTL elements properly in place (i.e., as in the CodePen mentioned). In short:
each word is formed of several <span> elements, each containing one letter.
following a specific time interval, each <span> that holds a letter gets applied an .in and .out CSS class. This goes on indefinitely.
here is what it looks like in the DOM:
the problem is that no matter what CSS selectors I use, I can't target the .in and .out classes, unless I do it via Developer Tools in Chrome:
original output:
output after I added the classes in Developer Tools:
Here is the bare minimum code of my Vue Component:
<template>
<div id="app-loading">
<div class="words">
<span v-for="setting in settings" v-html="setting.lettersHTML" :id="setting.id" class="word"></span>
</div>
</div>
</template>
<script>
export default {
data() {
return {
settings: [
{ word: 'WordOne', id: 1, lettersArray: null, lettersHTML: null },
{ word: 'WordTwo', id: 2, lettersArray: null, lettersHTML: null }
],
currentWord: 1
}
},
created() {
this.splitLetters();
},
mounted() {
setInterval(this.changeWord, 1500);
},
methods: {
splitLetters() {
this.settings.forEach((setting) => {
let letters = [];
for (let i = 0; i < setting.word.length; i++) {
let letter = `<span class="letter">${ setting.word.charAt(i) }</span>`;
letters.push(letter);
}
setting.lettersArray = letters;
setting.lettersHTML = letters.join('');
});
},
changeWord() {
let current = document.getElementById(this.currentWord).getElementsByTagName('span');
let next = (this.currentWord == this.settings.length) ? document.getElementById(1).getElementsByTagName('span') : document.getElementById(this.currentWord + 1).getElementsByTagName('span');
// Animate the letters in the current word.
for (let i = 0; i < current.length; i++) {
this.animateLetterOut(current, i);
}
// Animate the letters in the next word.
for (let i = 0; i < next.length; i++) {
this.animateLetterIn(next, i);
}
this.currentWord = (this.currentWord == this.settings.length) ? 1 : this.currentWord + 1;
},
animateLetterOut(current, index) {
setTimeout(() => {
current[index].className = 'letter out';
}, index * 300);
},
animateLetterIn(next, index) {
setTimeout(() => {
next[index].className = 'letter in';
}, 340 + (index * 300));
}
}
}
</script>
<style lang="scss" scoped>
#app-loading {
font-size: 4rem;
}
.words, .word {
border: 1px solid rosybrown;
}
.letter {
text-decoration: underline; // Not working.
}
.letter.in {
color: red; // Not working.
}
.letter.out {
color: blue; // Not working.
}
</style>
What goes wrong that prevents these classes from being applied?

You're using v-html, but that doesn't work with scoped styles.
DOM content created with v-html are not affected by scoped styles, but you can still style them using deep selectors.

This worked for me:
<template>
<div class="a" v-html="content"></div>
</template>
<script>
export default {
data() {
return {
content: 'this is a <a class="b">Test</a>',
}
},
}
</script>
<style scoped>
.a ::v-deep .b {
color: red;
}
</style>

Yes,
v-html
doesn't work with scoped styles.
As Brock Reece explained in his article Scoped Styles with v-html, it should be solved like this:
<template>
<div class="a" v-html="content"></div>
</template>
<script>
export default {
data() {
return {
content: 'this is a <a class="b">Test</a>',
}
},
}
</script>
<style scoped>
.a >>> .b {
color: red;
}
</style>

Most answers are deprecated now that Vue3 is out.
Up-to-date usage of deep selector:
.letter{
&:deep(.in) {
color:blue;
}
&:deep(.out) {
color:red;
}
}

Vue3: In Single-File Components, scoped styles will not apply to content inside v-html, because that HTML is not processed by Vue's template compiler.
You can use :deep() inner-selector in Vue3 project.
Here is a example:
<script setup lang="ts">
import {onMounted,ref } from 'vue'
const content = ref("")
onMounted(()=>{
window.addEventListener('keydown',event =>{
content.value = `
<div class="key">
<span class="content">${event.keyCode}</span>
<small>event.keyCode</small>
</div>
`
})
})
</script>
<template>
<div class="container" v-html="content">
</div>
</template>
<style lang="scss" scoped>
.container{
display: flex;
:deep(.key){
font-weight: bold;
.content{
font-size: 1.5rem;
}
small{
font-size: 14px;
}
}
}
</style>

Related

Vue multiple components and access to Vuex properties

I'm learning Vue, using it with Vuex (without Webpack), but I have several questions when implementing this simple example, it's not clear for me in the docs.
Don't know why, but, I can't access the Vuex store using this pointer inside component computed property, for example:
this.$store.state.nav.title, leading me to use global app variable instead. Also, this.$parent and $root do not work.
Is it correct to initialize multiple Vue components at one time such as this, and shouldn't they have been mounted automatically when I pass components property to the Vue construct object? What is the right way to initialize, for example, the header, footer and body components at the same time?
var app = new Vue({
el: document.getElementById('app'),
data: {
title:store.state.nav.title
},
computed: {},
methods:{},
mounted:function(){},
updated:function(){},
store:store,
components:{
componentheader,
componentnavbar,
componentbody,
componentfooter
}
});
for (var companent_name in app.$root.$options.components) {
if(typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Here is the full example:
var store = new Vuex.Store({
state: {
nav: {
title: 'my site'
}
},
mutations: {
changeTitle: function(t, a) {
this.state.nav.title = a;
}
}
});
var componentheader = Vue.component('componentheader', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#header_tpl',
mounted: function() {},
updated: function() {}
});
var componentnavbar = Vue.component('componentnavbar', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#navbar_tpl',
mounted: function() {},
updated: function() {}
});
var componentbody = Vue.component('componentbody', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#body_tpl',
mounted: function() {},
updated: function() {}
});
var componentfooter = Vue.component('componentfooter', {
computed: {
title() {
return app.$store.state.nav.title
}
},
template: '#footer_tpl',
mounted: function() {},
updated: function() {}
});
var app = new Vue({
el: document.getElementById('app'),
data: {
title: store.state.nav.title
},
computed: {},
methods: {},
mounted: function() {},
updated: function() {},
store: store,
components: {
componentheader,
componentnavbar,
componentbody,
componentfooter
}
});
Vue.use(Vuex);
for (var companent_name in app.$root.$options.components) {
if (typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent().$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Vue.config.devtools = false;
Vue.config.productionTip = false;
* {
margin: 0;
padding: 0;
color: #fff;
text-align: center;
font-size: 19px;
}
html,
body,
.container {
height: 100%;
}
#app {
position: relative;
height: 100%;
min-height: 100%;
}
header {
width: 100%;
height: 80px;
}
nav.navbar {
box-sizing: border-box;
min-height: 100%;
padding-bottom: 90px;
width: 80px;
height: 100%;
position: absolute;
}
.container {
box-sizing: border-box;
min-height: 100%;
padding-bottom: 90px;
color: #000;
}
footer {
height: 80px;
margin-top: -80px;
}
footer,
nav,
header {
background: #000;
}
header div,
footer div {
padding: 15px;
}
nav ul {
list-style-type: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.5.1/vuex.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="app">
</div>
<script type="text/x-template" id="header_tpl">
<header class="header">
<div>
header {{ title }}
</div>
</header>
</script>
<script type="text/x-template" id="navbar_tpl">
<nav class="navbar">
<ul>
<li>navbar {{ title }}</li>
</ul>
</nav>
</script>
<script type="text/x-template" id="body_tpl">
<div class="container">
<div>
body {{ title }}
</div>
</div>
</script>
<script type="text/x-template" id="footer_tpl">
<footer class="footer">
<div>
footer {{ title }}
</div>
</footer>
</script>
</body>
</html>
You seem confused about Vue Instance and Vue Component. Basically you only need just one Vue instance with multiple components to create your app.
To answer your first question, it does not work because you didn't install the store to each Vue instance that you are created (you only install just 1 instance called app).
for (var companent_name in app.$root.$options.components) {
if (typeof app.$root.$options.components[companent_name] === 'function') {
var MyComponent = Vue.extend(app.$root.$options.components[companent_name]);
var component = new MyComponent({
store // <-- install here
}).$mount();
document.getElementById('app').appendChild(component.$el);
}
}
Working example here
Actually you can just use store since all store and app.$store and this.$store is the same object. The advantage of this.$store is you have no need to import store to every component file for Single File Components.
To answer your second question,
You are mixing about Global Registration and Local Registration. You should use only one for a component.
For render components you can define your template inside <div id="app"> just like:
<div id="app">
<componentheader></componentheader>
<componentnavbar></componentnavbar>
<componentbody></componentbody>
<componentfooter></componentfooter>
</div>
Working example here

DOM element becomes Null in Vue project

I'm working on a code typer, but for some reason the element becomes Null with no reason I can make out. I am new to Vue & know this code works as I've previously completed this at https://CodeSpent.dev (live preview) in Django/Python until I determined it'd be valuable to learn more front end frameworks.
So I believe it has something to do with how Vue handles rendering, but I'm only a few hours into learning & have no idea where to even look with this.
Here is the code:
var codeBlock = document.getElementById('code')
console.log(codeBlock)
setTimeout(() => {
new TypeIt(codeBlock, {
strings: [codeSample],
speed: 20
}).go();
}, 1000)
setInterval(function () {
const code = Prism.highlight(codeBlock.innerText, Prism.languages.python, 'python');
document.getElementById('real-code').innerHTML = code;
}, 10);
If we look at console we can see on line 23 where codeBlock is clearly not null, but then when we try to use it it becomes null. Anything stand out?
Full Component:
<template>
<div id="code-block" class="bb">
<pre class="code-pre">
<code id="real-code"></code>
</pre>
<div id="code" class="language-py"></div>
</div>
</template>
<script>
import 'prismjs'
import 'prismjs/themes/prism.css'
import TypeIt from 'typeit';
export default {
name: 'CodeTyper'
}
var codeSample = '\x0a\x3E\x3E\x20\x6E\x61\x6E\x6F\x20\x63\x6F\x64\x65\x73\x70\x65\x6E\x74\x2E\x70\x79\x0A\x66\x72\x6F\x6D\x20\x70\x79\x74\x68\x6F\x6E\x20\x69\x6D\x70\x6F\x72\x74\x20\x44\x65\x76\x65\x6C\x6F\x70\x65\x72\x0A\x66\x72\x6F\x6D\x20\x70\x6F\x72\x74\x66\x6F\x6C\x69\x6F\x2E\x6D\x6F\x64\x65\x6C\x73\x20\x69\x6D\x70\x6F\x72\x74\x20\x50\x6F\x72\x74\x66\x6F\x6C\x69\x6F\x0A\x0A\x63\x6C\x61\x73\x73\x20\x43\x6F\x64\x65\x53\x70\x65\x6E\x74\x28\x44\x65\x76\x65\x6C\x6F\x70\x65\x72\x29\x3A\x0A\x20\x20\x20\x20\x6E\x61\x6D\x65\x20\x3D\x20\x27\x50\x61\x74\x72\x69\x63\x6B\x20\x48\x61\x6E\x66\x6F\x72\x64\x27\x0A\x20\x20\x20\x20\x6C\x6F\x63\x61\x74\x69\x6F\x6E\x20\x20\x3D\x20\x27\x50\x69\x74\x74\x73\x62\x75\x72\x67\x68\x2C\x20\x50\x41\x2C\x20\x55\x53\x27\x0A\x20\x20\x20\x20\x6C\x61\x6E\x67\x75\x61\x67\x65\x73\x20\x3D\x20\x5B\x27\x70\x79\x74\x68\x6F\x6E\x27\x2C\x20\x27\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x27\x2C\x20\x27\x63\x73\x73\x27\x2C\x27\x68\x74\x6D\x6C\x35\x27\x5D\x0A\x20\x20\x20\x20\x66\x61\x76\x6F\x72\x69\x74\x65\x73\x20\x3D\x20\x5B\x27\x64\x6A\x61\x6E\x67\x6F\x27\x2C\x20\x27\x74\x65\x6E\x73\x6F\x72\x66\x6C\x6F\x77\x27\x2C\x20\x27\x74\x77\x69\x74\x63\x68\x27\x2C\x20\x27\x64\x69\x73\x63\x6F\x72\x64\x27\x2C\x20\x27\x6F\x70\x65\x6E\x63\x76\x27\x5D\x0A\x0A\x20\x20\x20\x20\x64\x65\x66\x20\x5F\x5F\x73\x74\x72\x5F\x5F\x28\x73\x65\x6C\x66\x29\x3A\x0A\x20\x20\x20\x20\x20\x20\x72\x65\x74\x75\x72\x6E\x20\x73\x65\x6C\x66\x2E\x6E\x61\x6D\x65'
var codeBlock = document.getElementById('code')
console.log(codeBlock)
setTimeout(() => {
new TypeIt(codeBlock, {
strings: [codeSample],
speed: 20
}).go();
}, 1000)
setInterval(function () {
const code = Prism.highlight(codeBlock.innerText, Prism.languages.python, 'python');
document.getElementById('real-code').innerHTML = code;
}, 10);
</script>
<style>
#real-code {
color: #5c5edc;
}
#code-block {
background-color: #141D22;
color: #fff;
flex: 1;
height: 355px;
}
#code-block-sub {
background-color: rgb(34, 32, 35);
color: #fff;
width: 100%;
padding: 0 15px;
height: 150px;
}
#code,
#code-sub {
padding: 0px !important;
margin: 0px !important;
display: none;
color: #fff !important;
}
</style>
First a template that presents the partial string...
<template>
<div>
<pre>{{partialCode}}</pre>
<v-btn #click="startAppending()"></v-btn>
</div>
</template>
Then the partialCode string bound into data...
export default {
data () {
return {
partialCode: '',
// other data
}
},
You may want to start appending onCreate or some other lifecycle hook (or once you receive the code data asynchronously), but the key to the logic is that you can now just change the state of partialCode and let the DOM update itself...
methods: {
startAppending() {
this.partialCode = '' // start fresh each time
const code = Prism.highlight(codeBlock.innerText, Prism.languages.python, 'python')
let index = 0
let interval = setInterval(() => {
if (this.partialCode.length === code.length) {
clearInterval(interval)
} else {
this.partialCode = code.slice(0, index++)
}
}, 200);
},
// the other methods
}

Vue notification when component DOM changed

A prop change with no effect on the component's DOM triggers its updated function, unexpectedly.
https://jsfiddle.net/e5gyuorL/1/
Same result for v-html="markup()" or {{markup()}} or computed: { markup: ... }.
Docs for updated (https://v2.vuejs.org/v2/api/#updated) say:
Called after a data change causes the virtual DOM to be re-rendered and patched.
How does one catch actual DOM re-renders? If this is a FAQ, apologies; I looked at length.
The most straightforward way I can think of is to have the component store its innerHTML in a data item, and on each update check to see whether it has changed:
Vue.component('t-markdown', {
template: '#t-markdown',
data: {
innerHTML: ''
},
props: {src:String},
methods: {
markup: function() { return this.src.slice(0,11) },
},
updated: function() {
if (this.innerHTML !== this.$el.innerHTML) {
this.$parent.count++;
this.innerHTML = this.$el.innerHTML;
}
},
mounted() {
this.innerHTML = this.$el.innerHTML;
}
});
new Vue({
el: "#app",
data: {count:0, inp:'<b>src</b> '},
methods: {
change: function() { this.inp += '#' },
},
mounted() {
setTimeout(() => this.inp = '<i>changed!</i>', 7000);
}
})
body {
background: #20262E;
padding: 20px;
font-family: sans-serif, Helvetica;
}
#app {
background: #fff;
border-radius: 4px;
padding: 20px;
transition: all 0.2s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<t-markdown :src="inp"></t-markdown>
<button #click="change">change</button> updated: {{count}}
<div>
{{inp}}
</div>
</div>
<script type="text/x-template" id="t-markdown">
<div v-html="markup()"></div>
</script>

Vue v-for: iterate one element individually in an array

I'm looking to loop through an array of span tags and add is-active to the next one in line, every 3 seconds. I have it working but after the first one, it adds all the rest. How do I just pull that class from the active one and add it to the next array item?
I've read through the official documentation several times and there doesn't seem to be any mention of iterating individual items, just listing them all or pushing an item onto the list.
I'm not sure if 'index' comes in to play here, and how to grab the index of the span element to add/subtract is-active. what am I doing wrong?
var firstComponent = Vue.component('spans-show', {
template: `
<h1>
<span class="unset">Make</span>
<br>
<span class="unset">Something</span>
<br>
<span v-for="(span, index) of spans" :class="{ 'is-active': span.isActive, 'red': span.isRed, 'first': span.isFirst }" :key="index">{{ index }}: {{ span.name }}</span>
</h1>
`,
data() {
return {
spans: [
{
name: 'Magical.',
isActive: true,
isRed: true,
isFirst: true
},
{
name: 'Inspiring.',
isActive: false,
isRed: true,
isFirst: true
},
{
name: 'Awesome.',
isActive: false,
isRed: true,
isFirst: true
}
]
};
},
methods: {
showMe: function() {
setInterval(() => {
// forEach
this.spans.forEach(el => {
if (el.isActive) {
el.isActive = false;
} else {
el.isActive = true;
}
});
}, 3000);
}
},
created() {
window.addEventListener('load', this.showMe);
},
destroyed() {
window.removeEventListener('load', this.showMe);
}
});
var secondComponent = Vue.component('span-show', {
template: `
<span v-show="isActive"><slot></slot></span>
`,
props: {
name: {
required: true
}
},
data() {
return {
isActive: false
};
}
});
new Vue({
el: "#app",
components: {
"first-component": firstComponent,
"second-component": secondComponent
}
});
.container {
position: relative;
overflow: hidden;
width: 100%;
}
.wrapper {
position: relative;
margin: 0 auto;
width: 100%;
padding: 0 40px;
}
h1 {
font-size: 48px;
line-height: 105%;
color: #4c2c72;
letter-spacing: 0.06em;
text-transform: uppercase;
font-family: archia-semibold, serif;
font-weight: 400;
margin: 0;
height: 230px;
}
span {
position: absolute;
clip: rect(0, 0, 300px, 0);
}
span.unset {
clip: unset;
}
span.red {
color: #e43f6f;
}
span.is-active {
clip: rect(0, 900px, 300px, -300px);
}
<div id="app">
<div class="container">
<div class="wrapper">
<spans-show>
<span-show></span-show>
</spans-show>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
To achieve desired result, I'd suggest to change the approach a bit.
Instead of changing value of isActive for individual items, we can create a variable (e.g. activeSpan, that will be responsible for current active span and increment it over time.
setInterval(() => {
// Increment next active span, or reset if it is the one
if (this.activeSpan === this.spans.length - 1) {
this.activeSpan = 0
} else {
this.activeSpan++
}
}, 3000);
In component's template, we make class is-active conditional and dependent on activeSpan variable:
:class="{ 'is-active': index === activeSpan, 'red': span.isRed, 'first': span.isFirst }"
If you still need to update values inside spans array, it can be done in more simple way, via map for example. Also included such case as optional in solution below.
Working example:
JSFiddle
Sidenote: there is no need to add window listeners for load event, as application itself is loaded after DOM is ready. Instead, method can be invoked inside created hook. It is included in solution above.

How to conditionally add attributes to react DOM element

I have a scenario where I'm using React.js to create a div using the following code :
React.createElement('div', {}, "div content")
Some additional javascript processing will allow me afterwards to deduce if this div needs to have the className attribute set to" ClassA" or "ClassB" or if it shouldn't have className at all.
Is there a way in javascript to access the div that was created from the React DOM and to add to it the className attribute?
Note : I couldn't achieve this is JSX so I resorted to the createElement method.
Edit: it is worth to mention that i might need to conditionally add attributes other than className. For example, I might need to add to an anchor tag an "alt" attribute or not based on conditional logic.
Thank you in advance.
Use JSX spread. Build and object with props, modify it however you like and pass it to component like so:
const props = {
name: 'SomeName'
}
if (true) {
props.otherName = 'otherName';
}
return (
<SomeComponent {...props}/>
);
See that ... syntax? That spread operator do the job - all props will end up as separate attributes on your component.
Take a look at this plunk: http://www.webpackbin.com/4JzKuJ9C-
Since you were trying to initially have your logic in JSX. I have a jsx solution that uses state
class App extends React.Component {
constructor() {
super();
this.state = {
classValue: ''
}
}
handleClick = () => {
if(this.state.classValue == '') {
this.setState({classValue : 'green'});
}
else if(this.state.classValue == 'green') {
this.setState({classValue : 'blue'});
}
else {
this.setState({classValue : 'green'});
}
}
render() {
return (
<div>
<div className={this.state.classValue}>Hello World</div>
<button onClick={this.handleClick()}>Toggle</button>
</div>
)}
}
ReactDOM.render(<App/>, document.getElementById('app'));
.green {
background-color: green;
}
.blue {
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div id="app"></div>
The example shows how can you change your className similarly using state you can set whatever attributes you like to change.
You can use ES6 syntax to achieve the desired functionality
const yourComponentProps = {
[ifThisIsTrue ? 'useThisName' : 'useAnotherName']: 'yourDesiredValue',
};
return <YourComponent {...yourComponentProps} />
This is a quite normal situation in React and requires virtually no special handling.
Note: It is best to hand props down the component tree declaratively but if that is not an option you can bind listener functions in componentDidMount and unbind them in componentWillUnmount as shown in the following example. So long as they call setState, your component's render function will get triggered.
const { Component, cloneElement } = React
class Container extends Component {
constructor(props) {
super(props)
this.state = { classNames: [ 'foo' ] }
this.appendClassName = () => {
const { classNames } = this.state
this.setState({ classNames: [ ...classNames, `foo_${classNames.length}` ] })
}
}
componentDidMount() {
document.querySelector('button').addEventListener('click', this.appendClassName)
}
componentWillUnmount() {
document.querySelector('button').removeEventListener('click', this.appendClassName)
}
render() {
const { children } = this.props
const { classNames } = this.state
return <div className={classNames.join(' ')}>{children}</div>
}
}
ReactDOM.render(<Container>I am content</Container>, document.getElementById('root'))
.foo {
font-family: monospace;
border: 1px solid rgb(100, 50, 50);
font-size: 1rem;
border-style: solid;
border-width: 1px;
width: 50vw;
height: 50vh;
margin: auto;
display: flex;
align-self: center;
justify-content: center;
align-items: center;
}
.foo.foo_1 {
font-size: 1.5rem;
background-color: rgb(200, 100, 200);
}
.foo.foo_2 {
font-size: 2rem;
border-radius: 3px 7px;
background-color: rgb(180, 120, 200);
}
.foo.foo_3 {
border-style: dashed;
background-color: rgb(175, 130, 180);
}
.foo.foo_4 {
border-width: 2px;
background-color: rgb(160, 165, 170);
}
.foo.foo_5 {
border-width: 1rem;
background-color: rgb(150, 200, 150);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<button>Click me</button>
<div id="root"></div>
P.S. - Avoid using componentWillMount, it can lead to bugs in the lifecycle and there is talk that it may be removed in a future version of React. Always make async side-effect laden requests within componentDidMount and clean them up in componentWillUnmount. Even if you have nothing to render, you are best off rendering a placeholder component until your data arrives (best option for fast loading), or nothing at all.

Categories

Resources