Why did setState not work in this case in NextJS?

Viewed 5822

Hello everyone!
I have a problem - setState does not work in my NextJS + TS application.
I tried my state through ReactHooks, but nothing worked, changed the component into a classes, but nothing worked.
I tried to run this component on a newly created CRA application without TS. Everything worked there.

The component receives the array via props and renders it as buttons.
State contains two properties, currentActive and selected.
When the user clicks on the button, the first function is triggered which should update this.state.currentActive
then the second one which should update this.state.selected

In the this.setState function, I call a callback, which should print to the console that the state has been updated. But nothing is output, it looks like this.setState is not being called!

import React, { Component } from 'react';

import { SelectFieldComp } from './styles';

interface IProps {
  title: string;
  name: string;
  options: {
    id: number;
    text: string;
    active: boolean;
  }[];
  multiple?: boolean;
  setFieldValue?: any;
}

interface IState {
  currentActive: number[];
  selected: string[];
}

class SelectField extends Component<IProps, IState> {
  constructor(props: IProps) {
    super(props);
    this.state = {
      currentActive: [],
      selected: []
    };
  }

  updateCurrentActive = id => {
    const { multiple } = this.props;
    const { currentActive } = this.state;
    const newCurrentActive: number[] = multiple
      ? Object.assign([], currentActive)
      : [];

    if (multiple && newCurrentActive.indexOf(id) > 0) {
      newCurrentActive.splice(newCurrentActive.indexOf(id), 1);
    } else {
      newCurrentActive.push(id);
    }

    this.setState(
      () => ({ currentActive: newCurrentActive }),
      () => {
        console.log('update state in updateCurrentActive: ', this.state);
      }
    );
  };

  updateSelected = () => {
    const { currentActive } = this.state;
    const { options } = this.props;
    const newArr: string[] = [];

    options.forEach(item => {
      if (currentActive.indexOf(item.id) > 0) {
        newArr.push(item.text);
      }
    });

    this.setState(
      () => ({ selected: newArr }),
      () => {
        console.log('update state in updateSelected: ', this.state);
      }
    );
  };

  render() {
    const { currentActive, selected } = this.state;
    const { title, name, options, setFieldValue } = this.props;

    return (
      <SelectFieldComp>
        <h3>{title}</h3>
        <div>
          {options.map(({ id, text }) => {
            const classList = currentActive.indexOf(id) > 0 ? 'active' : '';

            return (
              <button
                key={id}
                type="button"
                className={classList}
                onClick={() => {
                  this.updateCurrentActive(id);
                  this.updateSelected();
                  setFieldValue(name, selected);
                }}
              >
                {text}
              </button>
            );
          })}
        </div>
      </SelectFieldComp>
    );
  }
}

export default SelectField;

1 Answers

The first parameter of this.setState() is an object and it looks like you're passing a function.

Try

 this.setState({ currentActive: newCurrentActive });

Immediately console logging after calling setState will also not work as the internals of setState are asynchronous so they may not be set yet.

You could console.log in your render method after this.props as this will show the state on the re-render of the component.

Related