Просмотр исходного кода

react day4:useEffect的使用

daxia 1 год назад
Родитель
Сommit
910a350231

+ 104 - 0
20_React.js_VIP22/React.js快速进坑.md

@@ -712,10 +712,114 @@ function TestUseState() {
 }
 ```
 
+另外,所有状态变量的修改函数 在修改状态时可能是异步的。因此在修改函数中 直接获取状态 用作上一次状态的值 可能是错误的
 
+```jsx
+import { useState } from 'react';
+
+export default function Counter() {
+  let [count, setCount] = useState(0);
+
+  function addOne() {
+    setCount(count + 1);
+  }
+  function reduceOne() {
+    setCount(count - 1);
+  }
+
+  return (
+    <div>
+      <h3>计数器</h3>
+      <p>值为:{count}</p>
+      <p>
+        <button onClick={addOne}>+</button>
+        <button onClick={reduceOne}>-</button>
+        <button
+          onClick={() => {
+            // setCount 这些修改函数 可能是异步的。
+            // 因此下面代码不能将count设置为 3
+            setCount(count + 1);
+            setCount(count + 1);
+            setCount(count + 1);
+          }}
+        >
+          +3
+        </button>
+      </p>
+    </div>
+  );
+}
+```
+
+上面 +3 按钮会失效。因此在连续调用setCount时参数count每一次都是0,也就是说 你调用三次`setCount(1)`。
+
+为了 能够在异步更新状态时准确获取到上一次状态,可以给所有修改函数传入一个 函数类型值,它可以接收两个参数:上一个状态值preState,以及组件属性props,然后该函数返回新状态。
+
+上面代码中,将setCount调用方式改为如下即可:
+
+```jsx
+setCount((preCount) => preCount + 1);
+setCount((preCount) => preCount + 1);
+setCount((preCount) => preCount + 1);
+```
+
+**小结**
+
+1. hook函数必须在函数组件中使用
+2. hook函数必须组件顶层中调用,不能在其他语句中使用
+3. useState中返回的修改函数 可能是异步修改状态
 
 ### 8.2 useEffect
 
+> Effect 译为 『副作用』。
+>
+> useEffect hook 就是在函数组件中执行副作用(和渲染无关)。
+>
+> useEffect是一个React Hook,可以让你将一个组件与外部系统同步。
+>
+> 其本质,就是用来实现一些生命周期的钩子。
+
+那么,useEffect 能帮助开发者实现那些生命周期钩子的效果呢?
+
+1. 每一次组件渲染时,都希望执行一些副作用
+
+   ```jsx
+   useEffect(() => {
+     // 编写一些副作用代码。注意: 别随意修改状态
+     // 组件每次渲染 都会执行
+   })
+   ```
+
+2. 仅当组件首次渲染后执行一些副作用
+
+   ```jsx
+   useEffect(() => {
+     // 仅会在组件首次渲染后执行一次,可以在这里发送http请求
+     // 模拟的就是componentDidMount钩子
+     console.log('===组件渲染后===');
+   }, []);
+   ```
+
+3. 在组件卸载前执行一些副作用
+
+   ```jsx
+   useEffect(() => {
+     // 返回一个回调函数
+     return () => {
+       // 这里返回的回调 会在组件卸载前执行
+       // 可以在这里清除一些『垃圾』
+       console.log('MsgItem卸载了');
+     };
+   }, []);
+   ```
+
+4. 监听state或者props,只要有一发生变化就会执行一些副作用
+
+   ```jsx
+   ```
+
+   
+
 ### 8.3 useMemo
 
 ### 8.4 useCallback

+ 5 - 1
20_React.js_VIP22/day-4/code/react-hooks-demo/src/App.js

@@ -1,11 +1,15 @@
 import './App.css';
 import TestUseState from './components/TestUseState';
+import Counter from './components/Counter';
+import TestUseEffect from './components/TestUseEffect';
 
 function App() {
   return (
     <div className="App">
       <header className="App-header">
-        <TestUseState />
+        {/* <TestUseState />
+        <Counter /> */}
+        <TestUseEffect />
       </header>
     </div>
   );

+ 37 - 0
20_React.js_VIP22/day-4/code/react-hooks-demo/src/components/Counter.jsx

@@ -0,0 +1,37 @@
+import { useState } from 'react';
+
+export default function Counter() {
+  let [count, setCount] = useState(0);
+
+  function addOne() {
+    setCount(count + 1);
+  }
+  function reduceOne() {
+    setCount(count - 1);
+  }
+
+  return (
+    <div>
+      <h3>计数器</h3>
+      <p>值为:{count}</p>
+      <p>
+        <button onClick={addOne}>+</button>
+        <button onClick={reduceOne}>-</button>
+        <button
+          onClick={() => {
+            // setCount 这些修改函数 可能是异步的。
+            // 因此下面代码不能将count设置为 3
+            // setCount(count + 1);
+            // setCount(count + 1);
+            // setCount(count + 1);
+            setCount((preCount) => preCount + 1);
+            setCount((preCount) => preCount + 1);
+            setCount((preCount) => preCount + 1);
+          }}
+        >
+          +3
+        </button>
+      </p>
+    </div>
+  );
+}

+ 53 - 0
20_React.js_VIP22/day-4/code/react-hooks-demo/src/components/TestUseEffect.jsx

@@ -0,0 +1,53 @@
+import { useEffect, useState } from 'react';
+
+function MsgItem({ text, title }) {
+  // 3 组件卸载前执行
+  useEffect(() => {
+    //
+    return () => {
+      // 这里返回的回调 会在组件卸载前执行
+      // 可以在这里清除一些『垃圾』
+      console.log('MsgItem卸载了');
+    };
+  }, []);
+
+  return (
+    <div>
+      <h3>{title}</h3>
+      <p>{text}</p>
+    </div>
+  );
+}
+
+export default function TestUseEffect({ name }) {
+  let [msg, setMsg] = useState('啥也没有');
+  // 1 每一次组件渲染 都有执行一些代码
+  useEffect(() => {
+    // 编写那些副作用代码
+    // console.log('==组件渲染==');
+  });
+
+  // 2 模拟 componentDidMount
+  useEffect(() => {
+    console.log('===组件渲染后===');
+  }, []);
+
+  return (
+    <div>
+      <h3>useEffect</h3>
+      <div>{msg && <MsgItem text={msg} title={'注意'} />}</div>
+      <p>
+        {msg}: {name}
+      </p>
+      <p>
+        <button
+          onClick={() => {
+            setMsg(Math.random() + '');
+          }}
+        >
+          change
+        </button>
+      </p>
+    </div>
+  );
+}