【问题标题】:transform Class based component to functional based component将基于类的组件转换为基于功能的组件
【发布时间】:2020-05-07 07:48:20
【问题描述】:

伙计们,我想转换此代码:

export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = { isLoading: true };
  }

  performTimeConsumingTask = async () => {
    return new Promise((resolve) =>
      setTimeout(() => {
        resolve('result');
      }, 2000)
    );
  };

  async componentDidMount() {
    const data = await this.performTimeConsumingTask();
    if (data !== null) this.setState({ isLoading: false });
  }

  render() {

    if (this.state.isLoading) return <SplashScreen />;

    const { state, navigate } = this.props.navigation;

    return (something)

我写了这段代码,但它不起作用:

const App = () => {
  const [fontLoaded, setFontLoaded] = useState(false);
  const [isTimerOn, setIsTimerOn] = useState(true);

  if (!fontLoaded) {
    return (
      <AppLoading
        startAsync={fetchFonts}
        onFinish={() => setFontLoaded(true)}
      />
    );
  }
  useEffect(async () => {
    const data = await performTimeConsumingTask();
    if (data !== null) setIsTimerOn(false);
  });
  if (isTimerOn) return <SplashScreen />;
  else {
    return (something)

这将显示一个错误: Invariant Violation: Rendered More Hooks than during the previous render.

如果我评论 useEffect 钩子,它将运行 splashScreen。谁能帮我转换一下?

【问题讨论】:

    标签: javascript react-native react-hooks


    【解决方案1】:

    如果您想将此钩子用作componentDidMount,请将[] 作为参数传递

    useEffect(async () => {
    const data = await performTimeConsumingTask();
    if (data !== null) setIsTimerOn(false);
    }, []); 
    

    这里是一个钩子列表,你可以如何使用钩子来替换生命周期方法

    https://medium.com/javascript-in-plain-english/lifecycle-methods-substitute-with-react-hooks-b173073052a

    出现错误的原因是您的组件渲染次数过多,并且 useEffect 也在每次渲染上运行,通过传递 [] 将在第一次渲染时运行 useEffect,因为它的行为类似于 componentDidMount。

    同样按照这个在useEffect内部进行网络调用

    https://medium.com/javascript-in-plain-english/handling-api-calls-using-async-await-in-useeffect-hook-990fb4ae423

    【讨论】:

    • 代码中还有很多其他错误。不仅仅是一个空的依赖。 OP提到的错误也与此无关
    【解决方案2】:

    在使用所有钩子之前必须没有条件返回,在您的情况下,您在使用useEffect 之前返回。

    此外,useEffect 不得在每次渲染上运行,因为它会在您的情况下设置状态。由于您只希望它在初始渲染时运行,因此传递一个空数组作为第二个参数。

    还有useEffect回调函数不能是异步的。

    在文档中阅读有关useEffect 挂钩的更多信息。

    检查下面的更新代码

    const App = () => {
      const [fontLoaded, setFontLoaded] = useState(false);
      const [isTimerOn, setIsTimerOn] = useState(true);
    
      const performTimeConsumingTask = async () => {
          return new Promise((resolve) =>
             setTimeout(() => {
               resolve('result');
            }, 2000)
       );
      };
      useEffect(() => {
        async function myFunction() {
           const data = await performTimeConsumingTask();
           if (data !== null) setIsTimerOn(false);
        }
        myFunction();
      }, []); // With empty dependency it runs on initial render only like componentDidMount
    
      if (!fontLoaded) {
        return (
          <AppLoading
            startAsync={fetchFonts}
            onFinish={() => setFontLoaded(true)}
          />
        );
      }
      if (isTimerOn) return <SplashScreen />;
      else {
        return (something)
    

    【讨论】:

      猜你喜欢
      • 2021-11-27
      • 2020-10-27
      • 1970-01-01
      • 2020-09-27
      • 1970-01-01
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      • 2020-07-31
      相关资源
      最近更新 更多