componentWillReceiveProps,React Hook的componentDidUpdate

Den*_*bin 9 javascript reactjs react-hooks

我遇到两个挑战:

  • 即使按照React准则,不鼓励派生状态,但某些边缘情况仍然需要它。
    就带有React Hook的功能组件而言,如果我确实需要派生状态,那么与React Hook等效的实现是什么?在类component中,将在每个父渲染器的componentWillReceiveProps中更新

参见下面的代码示例:

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: props.count > 100 ? 100 : props.count,
    }

  }

  /*What is the equivalent implementation when React Hook is used here componentWillReceiveProps*/
  componentWillReceiveProps(nextProps) {
    if (nextProps.count !== this.props.count) {
      this.setState({
        count: nextProps.count > 100 ? 100 : nextProps.count
      });
    }
  }

  render() {
    return ( <
      div > {
        this.state.count
      } <
      /div>
    );
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

  • 至于componentDidUpdate,当使用React Hook时,componentDidUpdate具有它的couterpart,它是

    React.useEffect(()=> {return()=> {

      };
    }, [parentProp]);
    
    Run Code Online (Sandbox Code Playgroud)

    useEffect的第二个参数可确保仅在更改道具时才执行代码,但是如果我想根据多个道具的不同来执行各自的任务呢?如何用useEffect完成它?

参见下面的代码示例:

fgo*_*lez 38

componentWillReceive可以使用useEffect钩子完成与旧道具等效的反应钩子,只需指定我们要侦听依赖项数组中的更改的道具即可。

IE:

export default (props) => {

    useEffect( () => {
        console.log('counter updated');
    }, [props.counter])

    return <div>Hi {props.counter}</div>
}
Run Code Online (Sandbox Code Playgroud)

因为componentDidUpdate仅仅通过省略依赖数组,该useEffect函数将在每次重新渲染后调用。

IE:

export default (props) => {

    useEffect( () => {
        console.log('counter updated');
    })

    return <div>Hi {props.counter}</div>
}
Run Code Online (Sandbox Code Playgroud)

  • 在对这个主题进行了一些广泛的研究之后,我认为您对 componentWillReceiveProps 的解释是错误的。所以问题是替换 componentWillReceiveProps 很棘手,因为它是一个预渲染函数。React hooks 的情况并非如此。您可以使用 useRef() 存储前一个 prop,并将其与 useEffect 函数中的当前 prop 进行比较,以尝试复制该功能,但即使这样也可能不完全是 1:1 替换。 (6认同)

Tho*_*lle 5

您可以使用useMemo挂钩来存储计算,然后将props.count其作为第二个参数放入给定的数组中,以在值更改时重新计算该值。

const { useState, useEffect, useMemo } = React;

function App() {
  const [count, setCount] = useState(50);

  useEffect(() => {
    setTimeout(() => {
      setCount(150);
    }, 2000);
  }, []);

  return <DisplayCount count={count} />;
}

function DisplayCount(props) {
  const count = useMemo(() => props.count > 100 ? 100 : props.count, [props.count]);

  return <div> {count} </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)

更改单独的道具时执行单独效果的最简单方法是创建多个useEffect仅在其中一个单独的道具更改时才运行的钩子。

const { useState, useEffect } = React;

function App() {
  const [groupName, setGroupName] = useState('foo');
  const [companyName, setCompanyName] = useState('foo');

  useEffect(() => {
    setTimeout(() => {
      setGroupName('bar');
    }, 1000);
    setTimeout(() => {
      setCompanyName('bar');
    }, 2000);
  }, []);

  return <DisplayGroupCompany groupName={groupName} companyName={companyName} />;
}

function DisplayGroupCompany(props) {
  useEffect(() => {
    console.log("Let's say, I do want to do some task here only when groupName differs");
  }, [props.groupName])
  useEffect(() => {
    console.log("Let's say,I do want to do some different task here only when companyName differs");
  }, [props.companyName])

  return <div> {props.groupName} - {props.companyName} </div>;
}

ReactDOM.render(<App />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

<div id="root"></div>
Run Code Online (Sandbox Code Playgroud)


Win*_*ter 5

setCount将触发重新渲染。使用useEffectwith[count]作为依赖项数组将确保钩子仅setCountcount的值更改时调用。

这就是你如何替换componentWillReceiveProps你可能用旧的基于类的 React 风格编写的任何逻辑。我发现“每个渲染都有自己的道具和状态”原则很有用:如果您只想在特定道具更改时触发重新渲染,您可以有几个useEffect钩子。

useEffect(() => {
  count > 100 ? setCount(100) : setCount(count)
}, [count]) 
 
useEffect(() => {
  console.log('groupName has changed');
  // do something with groupName
}, [groupName])
    
useEffect(() => {
  console.log('companyName has changed');
  // do something with companyName
}, [companyName]) 
Run Code Online (Sandbox Code Playgroud)


jpm*_*rks 5

如果您在组件顶部使用 useMemo 钩子并使其依赖于您的所有道具,则每次道具更改时它都会在所有内容之前运行。useEffect 在更新渲染后触发,并且由于依赖于所有道具,因此它在根据所有道具重新渲染后触发。

const Component = (...props) => {
   // useState, useReducer if have
   useMemo(() => {
     // componentWillReceiveProps
   },[...props]);
   // ...other logic and stuff
   useEffect(() => {
     // componentDidUpdate
   }, [...props]);
};
Run Code Online (Sandbox Code Playgroud)