Javascript 如何在React钩子中使用componentWillMount()?

Javascript 如何在React钩子中使用componentWillMount()?,javascript,reactjs,jsx,react-hooks,Javascript,Reactjs,Jsx,React Hooks,React的官方文件中提到: 如果您熟悉React类生命周期方法,您可以 将效果挂钩用作componentDidMount、componentDidUpdate和 组件将联合卸载 我的问题是-我们如何在钩子中使用componentWillMount()lifecycle方法?根据reactjs.org,将来将不支持componentWillMount。 无需使用componentWillMount 如果要在安装组件之前执行某些操作,只需在构造函数()中执行即可 如果要执行网络请求,请不要在co

React的官方文件中提到:

如果您熟悉React类生命周期方法,您可以 将效果挂钩用作componentDidMount、componentDidUpdate和 组件将联合卸载


我的问题是-我们如何在钩子中使用
componentWillMount()
lifecycle方法?

根据reactjs.org,将来将不支持componentWillMount。

无需使用componentWillMount

如果要在安装组件之前执行某些操作,只需在构造函数()中执行即可

如果要执行网络请求,请不要在componentWillMount中执行。这是因为这样做会导致意外的错误

网络请求可以在componentDidMount中完成

希望能有帮助


更新日期:2019年3月8日

您请求componentWillMount的原因可能是因为您希望在呈现之前初始化状态

就在你的状态下做吧

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialize your state here
    return <p>{value}</p>
}
export default helloWorld;
使用hook,您只需删除lifecycle方法:

const hookComponent=()=>{
    console.log('componentWillMount')
    return <p>you have transfered componeWillMount from class component into hook </p>
}
useEffect在每个渲染上运行,它是componentDidUpdate、componentDidMount和ComponentWillUnmount的组合

 useEffect(()=>{},[])
如果我们在useffect中添加一个空数组,它将在安装组件时运行。这是因为useEffect将比较您传递给它的数组。 所以它不必是空数组,它可以是不变的数组。例如,它可以是[1,2,3]或['1,2']。useEffect仍仅在安装组件时运行

它取决于您希望它只运行一次还是在每次渲染后运行。如果您忘记添加数组,只要您知道自己在做什么,这并不危险

我为hook创建了一个示例。请检查一下


于2019年8月21日更新

我写上述答案已经有一段时间了。我认为你需要注意一些事情。 当你使用

useEffect(()=>{},[])
当react比较传递给数组[]的值时,它使用
Object.is()
进行比较。 如果将对象传递给它,例如

useEffect(()=>{},[{name:'Tom'}])
这与:

useEffect(()=>{})
它每次都会重新渲染,因为当
Object.is()
比较一个对象时,它比较的是它的引用,而不是值本身。这与{}=={}返回false的原因相同,因为它们的引用不同。 如果仍要比较对象本身而不是引用,可以执行以下操作:

componentWillMount(){
  console.log('componentWillMount')
}
useEffect(()=>{},[JSON.stringify({name:'Tom'})])
const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };

您不能在钩子中使用任何现有的生命周期方法(
componentDidMount
componentdiddupdate
componentWillUnmount
等)。它们只能在类组件中使用。对于挂钩,您只能在功能组件中使用。以下行来自React文档:

如果您熟悉React类生命周期方法,可以将
useEffect
Hook看作是
componentDidMount
componentDidUpdate
,以及
componentWillUnmount
的组合

建议是,您可以从功能组件中的类组件模拟这些生命周期方法

组件内部的代码在安装组件时运行一次<代码>使用效果此行为的挂钩等价物为

useEffect(() => {
  // Your code here
}, []);
注意这里的第二个参数(空数组)。这将只运行一次

如果没有第二个参数则会在组件的每个渲染上调用
useffect
钩子,这可能是危险的

useEffect(() => {
  // Your code here
});
componentWillUnmount
用于清理(如删除事件侦听器、取消计时器等)。假设您正在
componentDidMount
中添加事件侦听器,并在
componentWillUnmount
中删除它,如下所示

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}
上述代码的等效吊钩如下所示

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])

请记住,传递给useMemo的函数在渲染期间运行。 不要在那里执行渲染时通常不会执行的任何操作。 例如,副作用属于useEffect,而不是useMemo


useLayoutEffect
可以通过一组空的观察者(
[]
)来实现这一点,如果该功能实际上类似于
componentWillMount
——它将在第一个内容到达DOM之前运行——虽然实际上有两个更新,但它们在绘制到屏幕之前是同步的

例如:


function MyComponent({ ...andItsProps }) {
     useLayoutEffect(()=> {
          console.log('I am about to render!');
     },[]);

     return (<div>some content</div>);
}


函数MyComponent({…andItsProps}){
useLayoutEffect(()=>{
log('我将要渲染!');
},[]);
返回(某些内容);
}
使用初始化器/设置器或
useffect
useState
的好处在于,虽然它可以计算渲染过程,但用户不会注意到对DOM的实际重新渲染,并且它在第一次可注意到的渲染之前运行,
useffect
的情况并非如此。当然,缺点是第一次渲染时会稍微延迟,因为在绘制到屏幕之前必须进行检查/更新。不过,这确实取决于您的用例

我个人认为,
useMemo
在一些特殊情况下是可以的,在这些情况下,你需要做一些重要的事情——只要你记住这是一个例外,而不是正常情况。

useComponentWillMount hook
const useComponentWillMount=(func)=>{
const willMount=useRef(真)
if(willMount.current)func()
willMount.current=false
}
我的经验是,当出现计时问题(在另一个脚本之前运行)时,这样的钩子可能是一种节省。如果不是这样,请使用更符合React-hooks范式的useComnponentDidMount

讨论

类内组件componentWillMount被视为遗留(,)。然而,这不应该应用于基于函数钩子的解决方案。类组件componentWillMount不推荐使用,因为它可能会运行多次,还有一种替代方法-使用构造函数。这些考虑因素并不重要
const Component = (props) => {
  useComponentWillMount(() => console.log("Runs only once before component mounts"));
  useComponentDidMount(() => console.log("Runs only once after component mounts"));
  ...

  return (
    <div>{...}</div>
  );
}
import { useState, useEffect } from 'react'

export default (fun) => {
  const [hasRendered, setHasRendered] = useState(false)

  useEffect(() => setHasRendered(true), [hasRendered])

  if (!hasRendered) {
    fun()
  }
}
import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'


export default () => { 
  useBeforeFirstRender(() => {
    console.log('Do stuff here')
  })

  return (
    <div>
      My component
    </div>
  )
}
useEffect(() => {
    console.log('componentDidMount');

    return () => {
        console.log('componentWillUnmount');
    };
}, []);
const InjectWillmount = function(Node, willMountCallback) {
  let isCalled = true;
  return function() {
    if (isCalled) {
      willMountCallback();
      isCalled = false;
    }
    return Node;
  };
};
const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.log("your pre-mount logic here");
});
const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props
useEffect(() => {
  // Your code here
  console.log("componentDidMount")
}, []);
const Component = () => {
   useMemo(() => {
     // componentWillMount events
   },[]);
   useEffect(() => {
     // componentDidMount events
     return () => {
       // componentWillUnmount events
     }
   }, []);
};
const MyComponent = () => {
  const [counter, setCounter] = useState(0)
  
  useEffect(() => {
    console.log('after render')
  })

  const iterate = () => {
    setCounter(prevCounter => prevCounter+1)
  }

  const beforeRender = () => {
    console.log('before render')
  }

  beforeRender()

  return (
    <div>
      <div>{counter}</div>
      <button onClick={iterate}>Re-render</button>
    </div>
  )
}

export default MyComponent
 useEffect(() => {
    return () => {
        console.log('componentWillUnmount');
    };
   }, []);
useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
const runOnceBeforeRender = () => {};

const Component = () => {
  useState(runOnceBeforeRender);

  return (<></>);
}
const runOnceBeforeRender = () => {};

const useOnInitialRender = (fn) => {
  useState(fn);
}

const Component = () => {
  useOnInitialRender(fn);

  return (<></>);
};