如何使用钩子将功能组件转换为 class 组件

How to convert functional component using hooks to class component

我正在尝试挑战自己,将使用挂钩的课程项目转换为同一个项目,但不必使用挂钩,以便了解有关如何使用 class 组件进行操作的更多信息。目前,我需要帮助弄清楚如何在普通 class 组件中复制 useCallback 挂钩。这是它在应用程序中的使用方式。

export const useMovieFetch = movieId => {
    const [state, setState] = useState({});
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(false);

    const fetchData = useCallback(async () => {
        setError(false);
        setLoading(true);

        try{
            const endpoint = `${API_URL}movie/${movieId}?api_key=${API_KEY}`;
            const result = await(await fetch(endpoint)).json();
            const creditsEndpoint = `${API_URL}movie/${movieId}/credits?api_key=${API_KEY}`;
            const creditsResult = await (await fetch(creditsEndpoint)).json();
            const directors = creditsResult.crew.filter(member => member.job === 'Director');
            
            setState({
                ...result,
                actors: creditsResult.cast,
                directors
            });

        }catch(error){
            setError(true);
            console.log(error);
        }
        setLoading(false);
    }, [movieId])

useEffect(() => {
        if(localStorage[movieId]){
            // console.log("grabbing from localStorage");
            setState(JSON.parse(localStorage[movieId]));
            setLoading(false);
        }else{
            // console.log("Grabbing from API");
            fetchData();
        }
    }, [fetchData, movieId])

    useEffect(() => {
        localStorage.setItem(movieId, JSON.stringify(state));
    }, [movieId, state])

    return [state, loading, error]
}

我了解如何复制其他挂钩,例如 useStateuseEffect,但我正在努力寻找替代 useCallback 的答案。感谢您为这个问题付出的努力。

您可以通过对给定输入使用记忆函数来复制useCallback的行为(例如:movieId

您可以使用lodash method

for more in-depth understanding check here

TL;DR

在您的特定示例中,useCallback 用于生成引用维护的 属性 以作为道具传递给另一个组件。您只需创建一个 bound 方法即可做到这一点(您不必像使用钩子那样担心 dependencies,因为所有依赖项都作为道具或状态在您的实例上维护。

class Movie extends Component {

    constructor() {
        this.state = {
            loading:true,
            error:false,
        }
    }

    fetchMovie() {
        this.setState({error:false,loading:true});

        try {
            // await fetch
            this.setState({
                ...
            })
        } catch(error) {
            this.setState({error});
        }
    }

    fetchMovieProp = this.fetchMovie.bind(this); //<- this line is essentially "useCallback" for a class component

    render() {
        return <SomeOtherComponent fetchMovie={this.fetchMovieProp}/>
    }

}

更多关于函数式 vs class 组件的钩子

useCallback 的美妙之处在于,要在 class 组件上实现它,只需声明一个实例 属性,它是一个函数(绑定到实例),然后您重新完成。

useCallback 的目的是引用完整性,因此,基本上,您的 React.memoReact.PureComponent 将正常工作。

const MyComponent = () => {
  const myCallback = () => { ... do something };
  return <SomeOtherComponent myCallback={myCallback}/> // every time `MyComponent` renders it will pass a new prop called `myCallback` to `SomeOtherComponent`
}
const MyComponent = () => {
  const myCallback = useCallback(() => { ... do something },[...dependencies]);
  return <SomeOtherComponent myCallback={myCallback}/> // every time `MyComponent` renders it will pass THE SAME callback to `SomeOtherComponent` UNLESS one of the dependencies changed
}

要在 class 组件中复制 useCallback,您无需执行任何操作:

class MyComponent extends Component {

   method() { ... do something }

   myCallback = this.method.bind(this); <- this is essentially `useCallback`

   render() {
     return <SomeOtherComponent myCallback={this.myCallback}/> // same referential integrity as `useCallback`
   }

}

大班轮

你会发现 React 中的 hooks 只是一种创建实例变量的机制(提示:“实例”是一个 Fiber),而你只有一个函数。