Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nextjs React SSR with styled-jsx - Cannot read property 'state' of undefined

I have stumbled upon a problem which I cannot seem to resolve. I tried to search here for the solution but was unable to help myself. I am a newbie in javascript and react so be considerate.

Problem: I am using React (16.5.0) with nextjs (6.1.2) with styled-jsx like so:

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Link from 'next/link';

class ProductCard extends Component {
    constructor(props) {
        super(props);
        this.state = {imgLoaded: false};
        this.imgHasLoaded = this.imgHasLoaded.bind(this);
    }

    imgHasLoaded() {
        this.setState({imgLoaded:true})
    }

    render() {
        return (
            <div className="thumbnail-container">
                <div className="loader-box">
                    <img src={require("../static/loading.png")} className="loading-img" />
                </div>
                <img src={this.props.imgSrc} className="main-img" onLoad={this.imgHasLoaded} />
                <div className="thumbnail-text">
                    {this.props.text}
                </div>
                <ul className="item-list">
                    {this.props.links.map(link =>
                        <li className="item">
                            <span className="item-span"> {link.text} </span>
                            {link.subLinks &&
                                <ul className="sub-item-list">
                                    {link.subLinks.map(subLink => <li>{subLink.text}</li>)}
                                </ul>
                            }
                        </li>
                    )}
                </ul>
                <style jsx> {`
                    .thumbnail-container {
                        user-select: none;
                        position: relative;
                        text-align: center;
                        width: 98%;
                        height: 98%;
                        margin: 1%;
                        display: block;
                        border: 0.3px solid black;
                        overflow: hidden;
                        border-radius: 10px;
                        box-shadow: 0 0 20px 0px rgba(0, 0, 0, 0.5);
                        overflow: hidden;
                        align-items: center;
                    }
                    .thumbnail-text {
                        position: absolute;
                        width: 100%;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        color: #ffffff;
                        font-size: 1.8em;
                        background-color: #333;
                        padding: 5px;
                        border-radius: 5px;
                        text-shadow: 1px 1px #000000;
                        text-transform: uppercase;
                        box-shadow: 0 5px 10px 0px rgba(0, 0, 0, 1);
                        transition: all 0.2s ease;
                    }
                    .thumbnail-container:hover .thumbnail-text, .thumbnail-container:focus .thumbnail-text, .thumbnail-container:active .thumbnail-text {
                        top: 0;
                        transform: translate(-50%, 0);
                        background-color: rgba(255, 124, 4, 0.9);
                        color: #000000;
                        text-shadow: none;
                    }
                    .main-img {
                        width: 100%;
                        height: 100%;
                        border-radius: 8px;
                        margin: auto;
                        -webkit-filter: grayscale(40%) contrast(120%) brightness(110%) saturate(120%);
                        -moz-filter: grayscale(40%) contrast(120%) brightness(110%) saturate(120%);
                        filter: grayscale(40%) contrast(120%) brightness(110%) saturate(120%);
                        opacity: ${this.state.imgLoaded ? 1 : 0};
                    }
                    .thumbnail-container:hover .main-img, .thumbnail-container:focus .main-img, .thumbnail-container:active .main-img{
                        -webkit-filter: grayscale(40%) contrast(120%)  saturate(120%) brightness(30%);
                        -moz-filter: grayscale(40%) contrast(120%)  saturate(120%) brightness(30%);
                        filter: grayscale(40%) contrast(120%)  saturate(120%) brightness(30%);
                    }
                    .item-list {
                        display: none;
                        position: absolute;
                        bottom: 0;
                        left: 0;
                        height: calc(100% - 2em);
                        flex-flow: column wrap;
                        justify-content: space-around;
                        list-style-type: none;
                    }
                    .thumbnail-container:hover .item-list, .thumbnail-container:focus .item-list, .thumbnail-container:active .item-list{
                        display: flex;
                    }
                    .item {
                        font-size: 1.3em;
                        display: flex;
                        flex-flow: column wrap;
                    }
                    .item-span {
                        padding-left: 8px;
                        border-bottom: solid #ff7c04;
                        border-left: solid #ff7c04;
                        transition: border-bottom 0.2s ease;
                    }
                    .item:hover .item-span, .item:focus .item-span, .item:active .item-span{
                        border-bottom: none;
                    }
                    .sub-item-list {
                        margin-left: 8px;
                        margin-top: 8px;
                        border-bottom: solid #ff7c04;
                        border-left: solid #ff7c04;
                        height: auto;
                        flex: 0;
                        overflow: hidden;
                        transition: flex 0.2s ease;
                    }
                    .item:hover .sub-item-list, .item:focus .sub-item-list, .item:active .sub-item-list{
                        flex: 1;
                    }
                    .loader-box {
                        position: absolute;
                        top: 50%;
                        left: 50%;
                        transform: translate(-50%, -50%);
                        width: 48px;
                        height: 48px;
                    }
                    .loading-img {
                        -webkit-animation: rotate-scale-up 1s linear infinite both;
                        animation: rotate-scale-up 1s linear infinite both;
                    }

                    @-webkit-keyframes rotate-scale-up {
                      0% {
                        -webkit-transform: scale(1) rotateZ(0);
                                transform: scale(1) rotateZ(0);
                      }
                      50% {
                        -webkit-transform: scale(1.5) rotateZ(180deg);
                                transform: scale(1.5) rotateZ(180deg);
                      }
                      100% {
                        -webkit-transform: scale(1) rotateZ(360deg);
                                transform: scale(1) rotateZ(360deg);
                      }
                    }
                    @keyframes rotate-scale-up {
                      0% {
                        -webkit-transform: scale(1) rotateZ(0);
                                transform: scale(1) rotateZ(0);
                      }
                      50% {
                        -webkit-transform: scale(1.5) rotateZ(180deg);
                                transform: scale(1.5) rotateZ(180deg);
                      }
                      100% {
                        -webkit-transform: scale(1) rotateZ(360deg);
                                transform: scale(1) rotateZ(360deg);
                      }
                    }


                    a {
                        text-decoration: none;
                    }
                    @media only screen and (max-width: 700px) {
                        .thumbnail-container {
                            width: 96%;
                            height: 96%;
                            margin: 2%;
                        }
                        .thumbnail-text {
                            height: 1.5em;
                            font-size: 1em !important;
                        }
                        .item-list {
                            height: calc(100% - 3em) !important;
                        }
                    }
                `}
                </style>
            </div>
        );
    }
}

However when using code above I get

Cannot read property 'state' of undefined

error in render function at line 26 (where item-list begins). The problem has something to do with using

opacity: ${this.state.imgLoaded ? 1 : 0};

in styled-jsx, because without this line, code works well.

Interestingly if I remove the item-list and its contents everything is working even with

opacity: ${this.state.imgLoaded ? 1 : 0};

I am sorry if this is something trivial or/and i forgot something fundamental. Just push me in the correct direction please

like image 483
Simon Obetko Avatar asked Nov 07 '22 00:11

Simon Obetko


1 Answers

ok i found out that my problem was related to styled jsx issue described here:

https://github.com/zeit/styled-jsx/issues/486

temporary workaround is to pull the imgLoaded into var and then use it in styled jsx.

Similar example here : https://github.com/zeit/next.js/issues/5735

like image 71
Simon Obetko Avatar answered Nov 15 '22 05:11

Simon Obetko