What causes this "maximum call stack size exceeded" error? - javascript

I am working on a Vue 3 and Bootstrap 5 app. I needed a date-picker and I choose Vue 3 Datepicker.
In components\Ui\Datepicker.vue I have:
<template>
<datepicker
#selected="handleSelect"
v-model="dateSelected"
:upper-limit="picked_to"
:lower-limit="picked_from"
class="datepicker text-center" />
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const dateSelected = ref(new Date());
return {dateSelected}
},
methods: {
handleSelect() {
this.$emit('setDate')
}
}
}
</script>
In components\Ui\Navigation.vue I have:
import Datepicker from './Datepicker'
export default {
inject: ['$apiBaseUrl'],
name: 'Navigation',
components: {
Datepicker,
},
data() {
return {
// more code
}
},
methods: {
setDate() {
this.$emit('setDate');
}
},
}
In components\Content.vue I have:
<template>
<div class="main">
<div class="d-sm-flex>
<h1>{{ title }}</h1>
<Navigation
#setDate='setDate'
/>
</div>
<div class="content">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.</p>
</div>
</div>
</template>
<script>
import Navigation from './Ui/Navigation'
export default {
inject: ['$apiBaseUrl'],
name: 'Content',
components: {
Navigation,
},
props: {
title: String,
},
emits: ['setDate'],
data() {
return {
headers: {
'content-type': 'application/json',
'Accept': 'application/json'
},
from: '',
to: '',
}
},
methods: {
sendData() {
this.axios.post(`${this.$apiBaseUrl}/submit`, this.fields, {options: this.headers}).then((response) => {
if (response.data.code == 200) {
this.isReport = true;
}
}).catch((errors) => {
this.errors = errors.response.data.errors;
});
}
},
setDate() {
console.log('Date');
},
}
}
</script>
The problem
Although I select a date from the datepicker, the setDate() method is not executed. The Chrome console shows instead:
Maximum call stack size exceeded
Where is my mistake?

As comments have mentioned previously, the error usually occurs when having an infinite loop.
As Kissu pointed out this can easily happen if you have an event that is emitted to a parent component which then changes data that is passed as props to a child component which then triggers an event to the parent and so on.
In the code you showed I can't really find any loops, they might be in the parts you omitted.
Edit:
The infinite loop could actually be caused by the naming of your component.
You're using <datepicker ...> inside Datepicker.vue without registering the Datepicker of vue3-datepicker there explicitly.
That probably causes vue to recursively try to mount the component in itself causing the maximum stack trace error, but that's just a guess.
But there's a couple issues in your code still.
First off:
<template>
<datepicker
#selected="handleSelect" // <-- according to the docs there are no events that the datepicker emits
v-model="dateSelected"
:upper-limit="picked_to" // <-- where does the picked_to value come from?
:lower-limit="picked_from" // <-- where does the picked_from value come from?
class="datepicker text-center" />
</template>
<script>
import { ref } from 'vue';
export default {
setup() {
const dateSelected = ref(new Date());
return {dateSelected}
},
// do not mix options & composition api
methods: {
handleSelect() {
this.$emit('setDate')
}
}
}
</script>
You're mixing options and composition API, which is never a good idea.
There's also a couple values that seemingly come from nowhere and you're listening to a #selected event from the datepicker, which according to the docs doesn't exist, so you'll have to watch for changes in the selected date yourself.
The same component in the composition API would look like this:
<template>
<Datepicker v-model="initialDate" class="datepicker text-center" />
</template>
<script>
import Datepicker from "vue3-datepicker";
import { ref, watch } from "vue";
export default {
components: { Datepicker },
setup(props, { emit }) {
const initialDate = ref(new Date());
watch(initialDate, (newDate) => {
emit("setDate", newDate);
});
return { initialDate };
},
};
</script>
I tried to recreate the example you gave in a sandbox and I do not encounter any infinite loop issues.
You might wanna check it out and compare with your code and possibly fix all the other issues first and see if that helps your situation :)

Related

Conditional output in dropdown component

I want to build a dropdown menu showing teachers who teach certain instruments (see image below)
The dropdown component is this:
import * as React from 'react'
import { useState, useEffect } from "react"
import { useStaticQuery, graphql } from 'gatsby'
import { BiChevronDown } from "react-icons/bi";
import StaffList from "./StaffList"
const rows = [
{
id: 1,
title: "Verantwortliche",
},
{
id: 2,
title: "Lehrende der Streichinstrumente",
instrument: "streichinstrumente"
},
{
id: 3,
title: "Lehrende der Zupfinstrumente",
},
{
id: 4,
title: "Lehrende des Tasteninstruments",
},
{
id: 5,
title: "Lehrende des Gesangs",
},
{
id: 6,
title: "Lehrende des Schlagzeugs",
},
{
id: 7,
title: "Lehrende des Akkordeons",
},
{
id: 8,
title: "Lehrende der Musiktheorie",
},
{
id: 9,
title: "Lehrende der Früherziehung",
}
]
class DropDownRows extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: false};
// This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
}
render() {
return (
<div className="dropdown-rows">
{rows.map(row => (
<div key={row.id}>
<div className="row">
<div className="col">{row.title}</div>
<div className="col">
<BiChevronDown
onClick={this.handleClick}
style={{float: "right"}}/>
</div>
<div>
</div>
</div>
{this.state.isToggleOn ? <StaffList /> : ''}
</div>
))}
</div>
)
}
}
export default DropDownRows
it uses this StaffList component:
import * as React from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import { MDXProvider } from "#mdx-js/react"
function StaffList({ data }) {
return(
<StaticQuery
query={graphql`
query staffQuery {
allMdx {
edges {
node {
excerpt(pruneLength: 900)
id
body
frontmatter {
title
description
featuredImage {
childImageSharp {
gatsbyImageData(
placeholder: BLURRED
)
}
}
}
}
}
}
}
`}
render={data => (
<div className="staff-container">
{data.allMdx.edges.map(edge => (
<article>
<div className="staff-image-container">
<GatsbyImage key={edge.node.id} alt='some alt text' image={getImage(edge.node.frontmatter.featuredImage)} style={{margin: "0 auto", padding: "0"}} />
</div>
<div style={{margin: "0 2em"}}>
<div>
<h4 key={edge.node.id} style={{margin: "0"}}>{edge.node.frontmatter.title}</h4>
<h5>{edge.node.frontmatter.description}</h5>
</div>
<p><MDXProvider>{edge.node.excerpt}</MDXProvider></p>
</div>
</article>
))}
</div>
)}
/>
)
}
export default StaffList
this is one of the .mdx files i source my data from:
---
title: Diana Abouem à Tchoyi
featuredImage: Foto_07.jpg
description: Violine, Streicherklassen
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Right now the component looks like this:
How would I conditionally render the content for each bar. so not all bars opening with the same content but just the one clicked showing only those teachers who fall in the selected category. My idea is to have some sort of conditional statement, comparing the selected bar title with maybe a field in the teachers markdown file? Like
title: Hanna
category: Streichinstrumente
and then if (allMdx.edges.node.frontmatter.category === rows.title) {...}
That's as far as I can wrap my head around this. Maybe someone can help? Thank you in advance.
I would have one array of objects storing teachers' datas. Example below.
const teacherData = [
{ id: 'piano',
name: "Alex",
otherData: ...
},
... (similarly for the rest)
]
Then another array of objects/records for instrument-teachers. Such as:
const records = [
{
id: 'piano',
teacher: []
}
]
After this I would loop through each element in the teacherData array to get the finalized record Array with id being the type of instrument and teachers being all the teachers that play that type of instruments.
Now, getting into the display part. I would write my component as below:
const Dashboard = () => {
const [show, setShow] = React.useState([])
function handleClick(id) {
if show.includes(id) {
const newShow = show.filter(a => a !== id)
setShow(newShow)
} else {
const newShow = show.push(id)
setShow(newShow)
}
}
return (
<div className="dashboard">
{records.map((record) =>
(
<div className="instrument-wrapper">
<p onClick={() => handleClick(record.id)} >{record.id}</p> //The name of the instrument
{show.includes(record.id) ? (
<div>
... all the teachers here by mapping through the record.teachers
</div>
) : (null)}
<div>
)
)}
</div>
)
}

How to get section to become sticky until the user has scrolled a specific length

I'm trying to replicate something similar to the Postmates fleet website, where they use position: sticky on a section and change elements within that section, until the user has scrolled through all the content.
Here's an example of what I mean:
So far I have set up a ref on the section I want to make sticky:
ref={(r) => this.ref = r}
...
/>
And then I get the height of the container on page load:
componentDidMount() {
if (this.ref) {
this.setState({ targetY: this.ref.getBoundingClientRect().bottom },
// tslint:disable-next-line:no-console
() => console.log(this.state, 'state'))
}
window.addEventListener('scroll', this.handleScroll)
}
After which I detect the scrolling of the page and know when the section is in view:
handleScroll(e) {
const scrollY = window.scrollY + window.innerHeight;
const { lockedIntoView, targetY } = this.state;
// tslint:disable-next-line:no-console
console.log(scrollY, "scrollY");
if (scrollY >= targetY) {
this.setState({ lockedIntoView: true }, () => {
// tslint:disable-next-line:no-console
console.log(`LockedIntoView: ${lockedIntoView}`);
});
} else {
this.setState({ lockedIntoView: false }, () => {
// tslint:disable-next-line:no-console
console.log(`LockedIntoView: ${lockedIntoView}`);
});
}
}
Before setting the container to sticky position:
<section
...
style={{position: lockedIntoView ? "sticky" : ""}}
...
</>
I would like to know how to make it like the postmates website, where the section just remains in full view of the screen until the content has been scrolled (or for right now, until the user has scrolled a specified height)?
Or just an idea of how they've done it, and what steps I need to take in order to replicate it?
Here's my Codesandbox
Few things to consider:
1) When you set the target to position: fixed, you are removing it from the dom flow so you need to compensate by adding some height back to the dom - example below does this on the body.
2) You need to factor in the height of the target when checking scrollY.
3) When you pass your target height, you add the target back into the dom flow and remove the additional height added in step 1.
4) You need to keep track if we scrolling up or down - this is done but comparing the last scroll position and the current.
See comments inline below for a rough example.
styles.css:
.lockedIntoView {
position: fixed;
top: 0;
}
index.js
import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
interface IProps {
title: string;
content: string;
}
interface IHeroState {
targetY: number;
lockedIntoView: boolean;
}
let lastScrollY = 0;
class App extends React.Component<IProps, IHeroState> {
ref: HTMLElement | null;
constructor(props) {
super(props);
this.handleScroll = this.handleScroll.bind(this);
this.state = {
lockedIntoView: false,
targetY: 0
};
}
componentDidMount() {
if (this.ref) {
this.setState(
{ targetY: this.ref.getBoundingClientRect().bottom },
// tslint:disable-next-line:no-console
() => console.log(this.state, "state")
);
}
window.addEventListener("scroll", this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener("scroll", this.handleScroll);
}
handleScroll(e) {
const scrollY = window.scrollY + window.innerHeight;
const { lockedIntoView, targetY } = this.state;
if (lockedIntoView) {
console.info("we locked");
// update the padding on the doc as we now removing the target from normal flow
window.document.body.style.paddingBottom = `${this.ref.getBoundingClientRect().height}px`;
// we passed the taret so reset - we have to factor the target height in the calc
if (scrollY > targetY + this.ref.getBoundingClientRect().height) {
window.document.body.style.paddingBottom = "0px";
this.setState({ lockedIntoView: false });
}
} else {
// if we scrollign down and at the target, then lock
if (
scrollY > lastScrollY &&
(scrollY >= targetY &&
scrollY < targetY + this.ref.getBoundingClientRect().height)
) {
console.info("we locked");
this.setState({ lockedIntoView: true });
}
}
// update last scroll position to determine if we going down or up
lastScrollY = scrollY;
}
render() {
const { lockedIntoView, targetY } = this.state;
const fixed = lockedIntoView ? "lockedIntoView" : "";
return (
<div className="App">
<div className="bg-near-white min-vh-100 ">
<h1>First section</h1>
</div>
<div
ref={r => (this.ref = r)}
className={`vh-100 bg-blue pa0 ma0 ${fixed}`}
>
<h2>
When this is in full view of the window, it should remain fixed
until the window has scrolled the full length of the window
</h2>
</div>
<div style={{ height: "300vh" }} className="bg-near-white min-vh-100 ">
<h2>The next section</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum.
</p>
</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
codesandbox demo

Vue.js recalculate computed properties on client after server rendering

I've got this simple vue single file component
<template>
<v-layout>
<v-flex xs12 sm6 offset-sm3>
<v-card v-bind:color="color" class="white--text">
<v-card-title primary-title>
<div>
<h3 class="headline mb-0">Kangaroo Valley Safari</h3>
<div>{{card_text}}</div>
</div>
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</template>
<script>
import MessageCard from '../components/MessageCard.vue';
const colors = [
'red',
'pink',
'purple',
'indigo',
'green'
];
export default {
data () {
return {
card_text: 'Lorem ipsum dolor sit amet, brute iriure accusata ne mea. Eos suavitate referrentur ad, te duo agam libris qualisque, utroque quaestio accommodare no qui.'
}
},
computed: {
color: function () {
const length = colors.length;
return colors[Math.round(-0.5 + Math.random() * (length + 1))] + ' darken-3';
}
},
components: {
MessageCard
}
}
</script>
The problem is that by server-side render I am getting computed color of v-card as a style, but when the client side hydration starts computed property recalculates which changes the style and causes rerender.
Of cause, I can fix it fix tag, but I'm curious is there some other ways to make it work correctly.
Computed properties are always reevaluated during client side hydration. It is generally not a good idea to relay on side effects in your computeds (like Math.random()), since Vue.js expects computed properties to be idempotent.
So usually you would calculate that random value once at creation and store it as data. However the data of a component is also not preserved between SSR and hydration.
So a way you could solve this, would be by storing the random value in the state of a Vuex store. It is then possible to restore the state of the store form the server in the client.

How is it possible to interpolate a JavaScript variable based on React state into another variable? [duplicate]

This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 4 years ago.
I have a React component pulling from a file with images, copy, and other data needed for the app. The issue I'm coming up against is simply syntactical: how can I reference this data based on the state of the component?
data.js looks like this (simplified version):
import changingAgents from '../public/images/changing-agents.jpg';
import cta from '../public/images/cta.jpg';
import logo from '../public/images/logo.jpg';
export const images = {
changingAgents,
cta,
logo,
}
export const copy = {
services: {
header: 'What are you looking for?',
firstTimeInvestor: {
title: 'First-Time Investor Service',
intro: 'At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque.',
},
changingAgents: {
title: 'Changing Agents',
intro: 'At vero eos et accusamus et iusto odio dignissimos ducimus, qui blanditiis praesentium voluptatum deleniti atque corrupti.',
},
}
And here are the relevant parts of the component, Services.js:
import { copy, images } from '../../data';
export default class Services extends Component {
state = {
segmentTrigger: 'changingAgents',
}
changeSegmentTrigger(chosenSegmentTrigger) {
this.setState({segmentTrigger: chosenSegmentTrigger})
}
render() {
return (
<div className="services">
<h2>{copy.services.header}</h2>
<Section backgroundImage={this.state.segmentTrigger} className="services__segment-triggers" >
<div className="services__segment-triggers__select">
<Button color="yellow" onClick={() => this.changeSegmentTrigger('firstTimeInvestor')} label="First-Time Investor" />
<Button color="yellow" onClick={() => this.changeSegmentTrigger('changingAgents')} label="Changing Agents" />
</div>
<div className="services__segment-triggers__info">
{/* Insert header here! */}
</div>
</Section>
</div>
)
}
}
Basically what I need to do is add text that will change depending on this.state.segmentTrigger in <div className="services__segment-triggers__info">. I tried a few variations to no avail, such as:
<h2>{copy.services.${this.state.segmentTrigger}.title}</h2>
<h2>{copy.services.${this.state.segmentTrigger}.title}`
<h2>{copy.services.this.state.segmentTrigger.title}</h2>
Is this possible? I get syntax errors for the first two, and the third one just doesn't work (which seems obviously logical to me, it was a bit of a Hail Mary even trying it, as of course there is no key named this in the copy.services object).
The answer you're looking for is
<h2>{copy.services[this.state.segmentTrigger].title}</h2>
The reasoning is that you're trying to access a key of copy.services, but that you will not know what key you're trying to access until the user starts clicking buttons, and which one you access will be dynamically decided.
The way objects and keys work in JavaScript, is that the key is technically a string, so using this example:
let x = {
test1: 4,
test2: 5,
'test3': 6
};
x.test1 // is 4
x.test2 // is 5
x.test3 // is 6
x['test1'] // is 4
x['test2'] // is 5
x['test3'] // is 6
const y = 'test1';
x.y // undefined. we never set a key of y.
x[y] // this is interpreted as x['test1'] so the result is 4

React / Redux - Cannot read property "XXX" of undefined

This is something I have been stuck on for over 2 weeks, so this question is my final chance at figuring this out. I hope anyone can help me (as the problem is most likely something small / something I have missed)
Using Node, Redux and React, I am returning a collection from my Mongo database.
I am using react-redux "connect" to retrieve my data from my store As seen in my JSX below.
JSX:
import React from "react";
import {connect} from "react-redux"
import {fetchArticle} from "../../actions/articleActions"
var classNames = require('classnames');
import GlobalHero from '../modules/GlobalHero.jsx';
#connect((store) => {
return {article: store.article.article, fetching: store.article.fetching};
})
export default class Article extends React.Component {
// BEFORE COMPONENT RENDER (For Everyhing else)
constructor() {
super();
//sets initial state
this.state = {
page: "Article"
};
}
// BEFORE COMPONENT RENDER (For Ajax / Dispatcher Events): get article Title / Thumbnail rows based on this.props.indexLimit
componentWillMount = () => {
console.log(this.props)
this.props.dispatch(fetchArticle(this.props.params.id))
}
// ON COMPONENT RENDER
componentDidMount = () => {}
render() {
if (this.props.fetching) {
return (
<p>Loading...</p>
);
} else {
return (
<div>
<h1>{this.props.article.title}</h1>
<h2>{this.props.article.subTitle}</h2>
</div>
);
}
}
}
My problem:
So when I return "title" and "subTitle" in my JSX, it pulls everything through perfectly fine (see below):
<h1>{this.props.article.title}</h1>
<h2>{this.props.article.subTitle}</h2>
The data is also visible on my screen (see below):
But... As soon as I add:
<h3>{this.props.article.body.section1.text}</h3>
My page will not load, and my console returns:
Cannot read property 'section1' of undefined
When I look at the state of my returned data in the console:
As you can see, it returns 'section1' in the console, so I must be calling my 'section1' wrong in my JSX?
I'm thinking the problem may be to do with the fact that 'section1' is nested further into my mongo db collection than 'title' or 'subTitle' is.
Below I will show you the rest of my routes for this page - I have looked endlessly online and cannot pinpoint my problem.
Action:
import axios from "axios";
//var resourceUrl = "http://localhost:7777/api/schools";
export function fetchArticle(id) {
return function(dispatch) {
dispatch({
type: "FETCH_ARTICLE"
})
axios.get('/api/article', {
params: {
id: id
}
})
.then((response) => {
dispatch({
type: "FETCH_ARTICLE_FULFILLED",
payload: response.data
})
})
.catch((err) => {
dispatch({
type: "FETCH_ARTICLE_REJECTED",
payload: err
})
})
}
}
Reducer:
export default function reducer(state = {
article: [],
fetching: false,
fetched: false,
error: null,
}, action) {
switch (action.type) {
case "FETCH_ARTICLE":
{
return {
...state,
fetching: true
}
}
case "FETCH_ARTICLE_REJECTED":
{
return {
...state,
fetching: false,
error: action.payload
}
}
case "FETCH_ARTICLE_FULFILLED":
{
return {
...state,
fetching: false,
fetched: true,
article: action.payload,
}
}
}
return state
}
Store:
import {
applyMiddleware,
createStore
} from "redux"
import logger from "redux-logger"
import thunk from "redux-thunk"
import promise from "redux-promise-middleware"
import reducer from "./reducers"
const middleware = applyMiddleware(promise(), thunk, logger())
export default createStore(reducer, middleware)
Node / Express Call:
app.get('/api/article', (req, res) => {
var ObjectId = require('mongodb').ObjectID;
var articles;
db.collection('articles')
.findOne({
"_id": ObjectId("58c2a5bdf36d281631b3714a")
})
.then(result => {
articles = result;
}).then(() => {
res.send(articles);
}).catch(e => {
console.error(e);
});
});
The Record in my mongo DB collection:
{
"_id": {
"$oid": "58c2a5bdf36d281631b3714a"
},
"title": "EntertheBadJah",
"subTitle": "Lorem ipsum dolor",
"thmbNailImg": "",
"headerImg": "",
"body": {
"section1": {
"include": true,
"text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
},
"section2": {
"include": true,
"text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
},
"bodyImg": {
"include": true,
"img": ""
},
"section3": {
"include": true,
"text": "Lorem ipsum dolor sit amet, dico posse integre cum ut, praesent iudicabit tincidunt te sea, ea populo semper laoreet duo."
}
},
"links": {
"recourse": {
"include": false,
"text": "Go watch their interview",
"link": ""
},
"soundcloud": {
"include": true,
"link": "www.soundcloud.com/BadJah"
},
"spotify": {
"include": false,
"link": ""
},
"youtube": {
"include": false,
"link": ""
},
"twitter": {
"include": false,
"link": ""
},
"facebook": {
"include": false,
"link": ""
},
"instagram": {
"include": false,
"link": ""
}
},
"keywords": "Badjah",
"date": "",
"author": "Aagentah",
"dateAdded": "2017-06-01T00:00:00.000Z"
}
Any help or advice on this problem is appreciated - thank you in advance.
React will rerender the page when its props (provided via Redux connect) change. Since you're only firing off the request to fetch the data in componentWillMount, by definition this will not have completed on the first render. However, that's no problem in the first case as this.props.article is guaranteed to be an object, [], so this.props.article.title will just be undefined. Once the request to the API returns, article is updated in the store and the page renders with the expected content.
However, since this.props.article is initially [], if you try to render this.props.article.body.section1.text, your code will throw an exception as observed since whilst article is an object, article.body is undefined. Having already thrown an error, the component will then fail to rerender when the article as actually updated in the store.
You need to add a guard to check the shape of this.props.article before trying to render subkeys, or else add a more complete default to the store for before the request returns with the actual article.
Try something like this. Could be that in the first render cycles its just not present yet.
checkRender(){
typeof this.props.article.body === 'undefined'
? return null
: return this.props.article.body.section1.text
}
Then use it ::>
<h3>{checkRender}</h3>
I can definitely recommend to add Flow type checks to your codebase (http://flow.org). It can be added on a file-per-file basis but can help significantly in debugging these kind of problems.

Categories

Resources