Boy Persoon
Boy Persoon

Reputation: 11

Cannot setState() on dynamically generated components

Let keyComponent filters a string for keywords and return them with an event handler(to toggle them) and generates a state (targetState) within this.state. The problem is that if I click on any of the keywords the state isn't updated/changed. I can see all the states being generated in this.state through console.log. they are simply not updating when clicked, no errors either.

I would appreciate some help ;-)

import React from 'react';
import { render } from 'react-dom';
import { sectionUpsert } from '/imports/api/userProgress/upsertMethods.jsx';


export default class LetsCheck extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            reference: props.reference,
            text: props.text,
            keys: props.keys,
            CorrectArray: [],

        };
    }

    handleClick(e, TxtBit, targetState) {
        console.log(targetState);
        console.log(this.state.targetState);
        let tempA = this.state.CorrectArray;
        let target = targetState;
        tempA.push(TxtBit);
        let obj = { [target]: true, }
        console.log(obj);
        this.setState(obj);

        // this.setState({
        //  CorrectArray: tempA,
        //  [target]: true,
        // });

        console.log(this.state);

    }

    handleUnclick(e, TxtBit, targetState) {
        console.log('unclicked' + TxtBit + index);
    }

    componentWillUnmount() {
        let keys = this.state.keys;
        let correct = this.state.CorrectArray;
        let keyWW = keys.filter(function(key){
            return !correct.includes(key) && keys.indexOf(key) % 2 === 0 
        });
        const secData = {
            userId: Meteor.userId(),
            ref: this.state.reference,
            keyWR: this.state.CorrectArray,
            keyWW: keyWW,
            porSect: Math.round((this.state.CorrectArray.length / (keyWW.length + this.state.CorrectArray.length)) * 100),
        };
        sectionUpsert.call(secData);
    }

    render() {
        let keys = this.state.keys;
        let clicked = this.state;
        let filter = keys.filter( function(key) {
            return keys.indexOf(key) % 2 === 0; 
        });
        let KeyComponent = this.state.text.map(function(TxtBit, index) {
            let match = false;
            let checkMatch = function(TxtBit, filter) {
                for (var y = filter.length - 1; y >= 0; y--) {
                    if ( TxtBit == filter[y] ) {
                        match = true 
                    }
                }
            };
            checkMatch(TxtBit, filter);
            if( match ) {
                targetState = 'KeyBtn' + index; 
                clicked[targetState] = false;
            return <a href="#" key={ index } style={{ display: `inline` }} onClick={ this.state[index] ? () => this.handleUnclick(this, TxtBit, targetState) : () => this.handleClick(this, TxtBit, targetState) } name={ TxtBit } className={ this.state[index] ? 'clicked': 'unclicked' } > { " "+TxtBit+ " " }</a>;
            } else {
                return <div  key={ index } style={{ display: `inline` }} className="TxtBit"> { " "+TxtBit+ " " }</div>;
            }
        }.bind(this)); 
        console.log(this.state);
        return(
            <div className="content">
              <div className="content-padded">
                    <div> {KeyComponent}</div>
                    <p> { this.state.CorrectArray.length } / {  this.state.keys.length / 2 } </p>


                </div>
            </div>
            );
    }
};

Upvotes: 0

Views: 75

Answers (1)

Jos&#233; Quinto Zamora
Jos&#233; Quinto Zamora

Reputation: 2128

Try to bind them: this.handleUnclick(this, TxtBit, targetState).bind(this)

or use arrow functions on handlers... example: https://blog.josequinto.com/2016/12/07/react-use-es6-arrow-functions-in-classes-to-avoid-binding-your-methods-with-the-current-this-object/

Regards!

Upvotes: 2

Related Questions