繁体   English   中英

通过父函数调用子函数时 this 未定义

[英]this is undefined when calling child function through a parent function

更新:我通过在打字稿文件中唱歌找到了一个更简单的解决方法,因此不再需要 JS 父级。 ~facepalm~感谢您的所有建议!

我正在尝试获取一个按钮来触发affTimer()组件内的函数affTimer()但我不断收到与函数调用相关的错误“这是未定义的”。 这是两个代码文件:

affType.js

import React, {Component}  from 'react';
import ReactPlayer from 'react-player'
import { Link } from 'react-router-dom';
import affirmationService from '../Services/requestService'
import affTrack from '../audio/inner.wav';
import warn from '../audio/warning.wav';
import Player from '../Player/Player';
import videoBG from '../videos/InnerStrength.mp4';
import Type from '../Type/Type.tsx';
import Button from "../customButton";
import {tXP} from '../Type/Type.tsx';

class affType extends Component {
  constructor(props) {
    super(props);
    this.state = {character: undefined};
    this.child = React.forwardRef();
    this.startGame = this.startGame.bind(this);
    
  }
  
  async componentDidMount() {
    const { match: { params } } = this.props;

    //let affirmation_id = params.affirmation_id;
    //let response = await affirmationService.getById(affirmation_id);
    //this.setState({character: response.data});
    setTimeout(() => {
      document.getElementById('overlay_blk_fast').style.opacity = 0;
      setTimeout(() => {
        document.getElementById('overlay_blk_fast').style.display = 'none';
      }, 1000);
    }, 10);
  }


  spawnDialog() {
    document.getElementById('overlay_1').style.display = 'block';
    setTimeout(() => {
      document.getElementById('overlay_1').style.opacity = 1;
    }, 10);

  }

  destroyDialog() {
    document.getElementById('overlay_1').style.opacity = 0;
    setTimeout(() => {
      document.getElementById('overlay_1').style.display = 'none';
    }, 1000);
  }
  repeat() {
    document.getElementById('overlay_2').style.opacity = 0;
    document.querySelector('video').play();
    setTimeout(() => {
      document.getElementById('overlay_2').style.display = 'none';
    }, 1000);
  }

  test_ended() {
    document.getElementById('overlay_2').style.display = 'block';
    setTimeout(() => {
      document.getElementById('audio_end').play();
      document.getElementById('overlay_2').style.opacity = 1;
    }, 10);
  }
  startGame() {
      var track = document.getElementById('aff');
      track.play();
      this.child.current.affTimer();
  }

  render() {
      
    return ( 
        <div>
        <div className="contentplayer">
            <audio id='aff'><source src={affTrack} /></audio>
            <video autoPlay muted loop id="myVideo">
           <source src={videoBG} type="video/mp4" />
            </video>      
            <audio id="audio_end" src="/Audio/Inner Strength completed quest - play with completed quest prompt.wav"/>
        </div>
        <p>{tXP}</p>
        <Button 
                border="none"
                color="pink"
                height = "200px"
                onClick={this.startGame}
                radius = "50%"
                width = "200px"
                children = "Start!"
            />
        <Type ref={this.child}> 
           
        </Type>

        <div className="aligntopright" onClick={() => {this.spawnDialog()}}>
          <div className="backbtn-white"></div>
        </div>
        
        <div className="overlay_blk_fast" id="overlay_blk_fast"></div>
        <div className="overlay" id="overlay_1">
          <div className="dialog">
            <div className="dialogcontainer">
              <img className="dialogbg"/>
              <h3 className="dialogtext">Are you sure you would like to go back to the selection page?</h3>
              <h2 className="no" onClick={() => {this.destroyDialog()}}>No</h2>
              <Link to="/affirmation"><h2 className="yes">Yes</h2></Link>
            </div>
          </div>
        </div>
        <div className="overlay" id="overlay_2">
          <div className="dialog">
            <div className="dialogcontainer">
              <img className="dialogbg"/>
              <h3 className="dialogtext">Would you like to repeat this quest?</h3>
              <Link to="/affirmation"><h2 className="no">Go back</h2></Link>
              <h2 className="yes" onClick={() => {this.repeat()}}>Repeat</h2>
            </div>
          </div>
        </div>
    </div>
    )
  }
}

export default affType;

类型.tsx

import React, {Component}  from 'react';
import useTypingGame from "react-typing-game-hook";
import { textSpanContainsTextSpan } from 'typescript';

var xpM = 0;
var i = 0;
var err = 0;
var xp = 5;
var tXP = 0;
var addXP = 1;
var bonus = 0;
var bonusCounter = 0;
//var warnP = new Audio({warn});
//var affTrackP = new Audio('../audio/inner.wav');

function TypeF() {

  
  let text_array = [
    "There is strength and solidity within me",
    "Courage is flooding through my veins",
    "I possess strength within my heart",
    "I am leading the charge with courage, and a vigorous resolution",
    "There is a force inside me that is unbelievably powerful",
    "There is a brave, radiant spirit inside me",
    "I am a tall tree, with thick and strong roots",
    "I was born for this",
    "There is a divinity within",
    "I am a force of nature",
    "I possess the mental fortitude of those who climb the highest peaks",
    "I was born with a determined spirit",
    "There is an intensity in my eyes"
  ];
 
  let text = text_array[i];

  const {
    states: {
      charsState,
      length,
      currIndex,
      currChar,
      correctChar,
      errorChar,
      phase,
      startTime,
      endTime
    },
    actions: { insertTyping, resetTyping, deleteTyping }
  } = useTypingGame(text);

  const handleKey = (key: any) => {
    if (key === "Escape") {
      resetTyping();
    } else if (key === "Backspace") {
      deleteTyping(false);
    } else if (key.length === 1) {
      insertTyping(key);
    }
  };

  

  if (currIndex + 1 === length) {
    xpM = xpM + 1;
    bonusCounter = bonusCounter + 1;
    err = err + errorChar;
    addXP = ((xp * correctChar) - (err * 2)) * xpM;
    if (err > correctChar) {
      addXP = correctChar * 3;
    }
    tXP = tXP + addXP;
    if (bonusCounter >= 5) {
      bonus = bonus + 1;
      bonusCounter = 0;
    }
    resetTyping();
  }
  
  var tmr;
  var cd = 18;

  function affTimer() {
    tmr = setInterval(tock, 1000);
    if (i >= text_array.length) {
      clearInterval(tmr);
    }
  }  

  function tock() {
    if (cd > 0) {
      cd = cd - 1;
      console.log(cd);
    }
    else if (cd <= 0) {
      if (i < text_array.length) {
        i = i + 1;
        cd = 18;
        resetTyping();
      }
      else {
        i = text_array.length;
      }
    }
  }


  return (
    
  <div className='container'>
     
  <div
    className="typing-test"
    id="start"
    onKeyDown={(e) => {
        handleKey(e.key);
        e.preventDefault();
      }
    }
    tabIndex={0}
  >
    {text.split("").map((char: string, index: number) => {
      let state = charsState[index];
      let color = state === 0 ? "white" : state === 1 ? "green" : "red";
      
      return (
        <span
          key={char + index}
          style={{ color }}
          className={currIndex + 1 === index ? "curr-letter" : ""}
        >
          {char}
        </span>
      );
    })}
  </div>
  <h2 className='debug'> TIMER: {cd}, I: {i}, ERRORS: {err},  MULTIPLIER: {xpM}, Type XP: {correctChar * xp}, CurrXP: {correctChar * xp * xpM} XPTotal: {tXP} bonusCounter: {bonusCounter}, BONUS: {bonus}</h2>
</div>
);

}
export {tXP};
export default TypeF;

任何帮助都会很棒,我已经坚持了 2 天,这是我需要完成的最后一点,以便我可以进入下一阶段。

您的子组件是一个功能组件。 您无法获得对函数组件实例的引用,因为没有实例。 如果你真的需要使用一个函数组件并且还需要公开一些自定义对象作为 ref,那么你可以使用useImperativeHandle钩子加上forwardRef来定义父组件应该在其 ref 上接收什么。 例如:

const Type = React.forwardRef((props, ref) => {
  // ...
  useImperativeHandle(ref, () => {
    // The following object is what will get assigned to the 
    //    parent component's this.child.current
    return {
      afftimer: function () {
        tmr = setInterval(tock, 1000);
        if (i >= text_array.length) {
          clearInterval(tmr);
        }
      }  
    }
  });

 // ...
})

但是useImperativeHandle并不是一个常用的东西。 可能有更标准的方法来解决您的问题。 父组件告诉子组件该做什么的正常方式是使用 props,而不是使用 refs。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM