tom harrison
tom harrison

Reputation: 3423

React run function within function

I am trying to run my function handleOpenDropDown when fastening.value is updated to drill_free.

The problem i'm having is that when the user selects an option and selectFastening runs and sets fastening.value to 'drill_free' it doesn't recognised that the value has been updated to drill_free until another option is selected then the function will run, so it is running after it supposed to.

How can I change my selectFastening function so that when fastening.value is set to drill_free the handleOpenDropDown function will run instantly

redux store

fastening { value: '', valid: '' }

fastening.js

export const settingDropName = 'fastening';
export const otherDropdownName = 'dimensions';    

class SettingDropFastening extends React.Component {
  constructor() {
    super()
    this.state = {
      showAlias: '',
      showImage: false,
    }
  }

  handleOpenDropdown = () => {
    this.props.close('fastening')
    this.props.openDropdownAlt('dimensions')
  }

  selectFastening = (fastening, name) => {
    this.props.selectFastening(fastening)
    this.props.selectedFastening.value === 'drill_free' && this.handleOpenDropdown()
  }

  closeDropdown = () => {
    this.props.showConfirmation ? this.props.closeDropdownWithConfirmation() : this.props.closeDropdown();
  }

  handleShowMontageImage = (alias) => {
    this.setState(prevState => ({
        //if same then reset otherwise assign new cat
      showAlias: prevState.showAlias === alias ? false : alias,
    }))
  }

  close = (name) => {
    this.props.close(name)
  }

  render() {
    const plissee = this.props.designation.alias === 'plissee'
    const rollo = this.props.designation.alias === 'rollo'
    const lamellen = this.props.designation.alias === 'lamellen'
    const holzJalousie = this.props.designation.alias === 'holzJalousie'
    const aluJalousie = this.props.designation.alias === 'aluJalousie'


    return (
      <SettingDrop
        title={"Befestigung"}
        closeDropdown={() => this.close('')}
        openDropdown={this.props.openDropdown}
        isOpen={this.props.isOpen}
        isHidden={this.props.isHidden}
        isValid={this.props.isValid}
        icon={<Befestigung />}
        option={
          (this.props.fastening.isValid && this.props.fastening.value)
          ?
          <span>
            <SelectedOptionLabel>Befestigung</SelectedOptionLabel>
            <SelectedOption>{this.props.fastening.value.name}</SelectedOption>
          </span>
          :
          <SelectedOptionSelect />
        }
        option2={
          ((this.props.fastening.isValid && this.props.fastening.value) && this.props.fastening.value.value !== null ||
          ((this.props.fastening.isValid && this.props.fastening.value) && this.props.fastening.value.value === null) &&
          this.props.selectedLateralGuidance === true) &&
          <span>
            <SelectedOptionLabel>Aufpreis</SelectedOptionLabel>
            <SelectedOption>
            {(this.props.fastening.value.type === ATTRIBUTE_TYPE_PRICE && this.props.fasteningCount) &&
              <span>
                {formatPrice(this.props.fastening.value.value * this.props.fasteningCount + (this.props.selectedLateralGuidance === true && 5))}
              </span>
            }
            {(this.props.fastening.isValid && this.props.fastening.value) &&
            (this.props.fastening.value.value === null && this.props.selectedLateralGuidance === true) &&
              <span>
                {formatPrice(5)}
              </span>
            }
            </SelectedOption>
          </span>
        }
      >
        <div>
        {console.log('selected fastening',this.props.selectedFastening)}
          {this.props.lateralGuidanceIsSelectable &&
            <div>
              <ShowSelect
                placeholder="Alle anzeigen"
                cat="Zusätzliche Seitenführung"
                width={220}
                options={[{
                  label: <span>Ja &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong>(Aufpreis 5,00 €)</strong></span> ,
                  value: 1
                }, {
                  label: 'Nein',
                  value: 0
                }]}
                value={this.props.selectedLateralGuidance ? 'Ja' : 'Nein'}
                onChange={ newValue => this.props.selectLateralGuidance(newValue && !!newValue.value) }
                designation={this.props.designation}
              />

            </div>
          }

          <div>
            <Description>Bitte wählen Sie Ihre Befestigungsart:</Description>
            <Grid>
              {this.props.fastenings.filter(fastenings => this.props.operationType === 'Schnurzug'
                ? (fastenings.alias !== 'bead_embroidery_fix' && fastenings.alias !== 'bead_embroidery_front_fix' && fastenings.alias !== 'drill_free')
                : fastenings)
                .map(fastening =>
                <Cell
                  key={fastening.alias}
                >
                <div>
              </div>
                  <ImageWrap
                    active={(this.props.fastening.isValid && this.props.fastening.value) && fastening.alias === this.props.fastening.value.alias}
                    name={fastening.name}
                    height={200}
                    key={fastening.alias}
                    onClick={
                      ((this.props.fastening.isValid && this.props.fastening.value) && fastening.alias === this.props.fastening.value.alias
                      ? null
                      : () => this.selectFastening(fastening.alias)
                      || this.props.selectedFastening.value === 'drill_free' ? () => this.handleOpenDropdown() : null
                      )
                    }
                    src={cdn(`images/fastenings/${this.props.designation}/${fastening.alias}.png`)}
                    alt={fastening.name}
                    price={((this.props.fastening.isValid && this.props.fastening.value) && fastening.alias === this.props.fastening.value.alias) &&
                    <div> {`Anzahl Montageteile: ${this.props.fasteningCount}`} &nbsp;&nbsp;&nbsp;<strong>{`(Aufpreis: ${formatPrice(fastening.value * this.props.fasteningCount)})`}</strong> </div>
                    }
                    designation={this.props.designation}
                    montageImages={
                      <div>
                        <MontageIcon onClick={() => this.handleShowMontageImage(fastening.alias)}>?</MontageIcon>
                          {montageImages.filter(montageImage => montageImage.name === this.props.designation).map((montageImage, index) =>
                            <div key={index}>
                               {(this.props.selectedModel !== 70 || this.props.selectedModel !== 52 )  &&
                                montageImage.images.filter((img => img.alias === fastening.alias && this.state.showAlias === img.alias))
                                .map((img, index) =>
                                  <MontageImageWrap key={index}>
                                    <MontageImage
                                      src={cdn(`images/montageparts/${this.props.designation}/${img.montageImg}`)}
                                      alt={fastening.name}
                                    />
                                  </MontageImageWrap>
                                )
                              }
                              {(this.props.selectedModel === 70 || this.props.selectedModel === 52 ) &&
                                 montageImage.images50.filter((img => img.alias === fastening.alias && this.state.showAlias === img.alias))
                                  .map((img, index) =>
                                    <MontageImageWrap key={index}>
                                      <MontageImage
                                        src={cdn(`images/montageparts/${this.props.designation}/${img.montageImg}`)}
                                        alt={fastening.name}
                                      />
                                    </MontageImageWrap>
                                  )
                              }
                            </div>
                          )}
                       </div>
                    }
                  />
                </Cell>
              )}
            </Grid>
          </div>
        </div>
      </SettingDrop>
    );
  }
};

const mapStateToProps = (state) => {

  const isOpen = state.ui.productSettings.openDropdown === settingDropName;
  const isHidden = !!state.ui.productSettings.openDropdown && !isOpen;
  const isValid = fasteningIsValid(state);

  return {
    designation: {
      ...mapDesignationName(state.model.designation.alias),
      alias: state.model.designation.alias
    },
    isOpen,
    isHidden,
    isValid,
    fastening: {
      value: getFastening(state),
      isValid: state.model.fastening.isValid
    },
    operationType: state.model.operationType.value,
    fasteningCount: getFasteningCount(state),
    showConfirmation: isValid ? false : !!state.model.fastening.value,
    fastenings: getFastenings(state),
    lateralGuidanceIsSelectable: !!getLateralGuidance(state, false),
    selectedLateralGuidance: state.model.lateralGuidance.value,
    fasteningCount: getFasteningCount(state),
    fasteningPrice: Number((getFastening(state) || {}).value) || 0,
    designation: state.model.designation.alias,
    selectedModel: state.model.model,
    selectedFastening: state.model.fastening
  };
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({
    ...settingDropActions,
  }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(SettingDropFastening);

Upvotes: 4

Views: 96

Answers (1)

Giorgi Moniava
Giorgi Moniava

Reputation: 28654

Here:

selectFastening = (fastening, name) => {
    this.props.selectFastening(fastening)
    this.props.selectedFastening.value === 'drill_free' && this.handleOpenDropdown()
  }

on the second line the props didn't get updated yet, so React still uses old props there.

You can put this logic:

   this.props.selectedFastening.value === 'drill_free' && this.handleOpenDropdown()

in componentDidUpdate. However, if something else afterwards triggers componentDidUpdate and value is still drill_free, it will again call the handleOpenDropDown() function. So you may want to protect yourself from this situation somehow.

You can check this (older) related issue, which uses componentWillReceiveProps, but you can apply same idea usingcomponentDidUpdate.

Upvotes: 4

Related Questions