为何从W3 Schools借鉴的typeWriter函数报‘not defined’错误?
Let's break down your problem step by step—first fixing that frustrating "typeWriter is not defined" error, then clearing up the confusion around the recursive function logic from the tutorial.
1. Why You're Seeing the Error
In your React component, typeWriter is an instance method (defined as an arrow function on the Hero class). When you pass typeWriter directly to setTimeout, JavaScript loses track of your component's context and tries to find a global function with that name (which doesn't exist—unlike the vanilla JS tutorial example, which uses a global function).
On top of that, your i variable is declared inside the typeWriter function, so it resets to 0 every time the function runs. That means you'd only ever print the first character of your message, even if the error was fixed!
2. Corrected Component Code
Here's the fixed version with key changes explained:
import React, { Component } from 'react'; class Hero extends Component { // Move tracking variables to the component instance so they persist between calls i = 0; message = 'I want to hike'; speed = 50; componentDidMount = () => { this.typeWriter(); } typeWriter = () => { if (this.i < this.message.length) { document.getElementById('typewriter-effect').innerHTML += this.message.charAt(this.i); this.i++; // Use an arrow function to preserve the component's `this` context setTimeout(() => this.typeWriter(), this.speed); } } render() { return ( <div className='banner-container'> <h1>iHike</h1> <h3>Find your adventure</h3> <p id='typewriter-effect'></p> </div> ) } } export default Hero;
What Changed:
- Instance-level variables:
i,message, andspeedare now attached to the component instance (this.iinstead of a locali). This keeps their values between calls totypeWriter, so we can track how many characters we've printed. - Arrow function in
setTimeout:() => this.typeWriter()ensures that when the timeout triggers, it calls thetypeWritermethod on your component instance, not searching for a global function.
3. Understanding the Recursive "Self-Invocation"
The tutorial's code uses recursion (the function calling itself) to create the typing effect. In vanilla JS, since the function is global, setTimeout(typeWriter, speed) works directly. But in React, methods are tied to component instances, so you need to explicitly reference this.typeWriter—and preserve the this context with an arrow function (or bind the method beforehand).
Each call to typeWriter adds one character, increments the counter, and schedules the next call via setTimeout. This repeats until all characters are printed.
Bonus: A More React-Friendly Approach
Instead of manipulating the DOM directly with document.getElementById, you can use React state to manage the displayed text—this is more aligned with React's data-driven philosophy:
import React, { Component } from 'react'; class Hero extends Component { state = { displayedText: '', message: 'I want to hike', speed: 50 }; componentDidMount() { this.typeWriter(); } typeWriter = () => { const { displayedText, message, speed } = this.state; if (displayedText.length < message.length) { this.setState(prevState => ({ displayedText: prevState.displayedText + message.charAt(prevState.displayedText.length) }), () => { // Schedule next call after state updates setTimeout(() => this.typeWriter(), speed); }); } } render() { return ( <div className='banner-container'> <h1>iHike</h1> <h3>Find your adventure</h3> <p>{this.state.displayedText}</p> </div> ) } } export default Hero;
This version uses React state to track the text, so React handles updating the UI automatically when the state changes—no direct DOM manipulation needed.
内容的提问来源于stack exchange,提问作者user8672583

