精华内容
下载资源
问答
  • useEffect钩子

    2020-09-21 15:54:52
    1. useEffect的返回函数(在组件销毁时执行的函数) useEffect被用于在函数组件中模拟生命周期。 在 useEffect 中,第二个参数的作用是监控变更条件,当参数中的数据发生变化之后,就会触发 useEffect 从而实现更新...

    1. useEffect的返回函数(在组件销毁时执行的函数)

    useEffect被用于在函数组件中模拟生命周期。

    举个例子:

    function MyComponent() {
        useEffect(() => {
            const timer = setInterval(
                () => console.log('hooooooook!'),
                1000
            );
            return () => clearInterval(timer);
        }, []);
        
        return (<div>Hello</div>);
    }
    

    在这个例子中,组件被挂载时会生成一个计时器,每一秒向控制台输出内容;
    在组件被销毁时,这个计时器也应该被清除,否则会造成内存泄漏;
    最后的返回函数 () => clearInterval(timer) 会在组件被销毁时执行,用于清除计时器。


    2. useEffect的第二个参数

    四个问题:

    1. 第二个参数的作用是什么?

    在 useEffect 中,第二个参数的作用是监控变更条件,当参数中的数据发生变化之后,就会触发 useEffect 从而实现更新;

    2. 为什么第二个参数是数组类型?

    因为需要监控的数据可能不止一个;

    3. 如果第二个参数留空会怎么样?

    如果留空,那么 useEffect 会在每次重新渲染之后执行;

    4. 如果传入一个空数组会怎么样?

    如果传入空数组,那么 useEffect 只会在初始化时执行一次。

    3. 在哪些情况下需要用useEffect这个hook?

    很多情况,因为它可以模拟生命周期。

    举个栗子,如果在进入页面的时候想调用一个API,那么就用useEffect,传入一个空数组,在初始化的时候就会执行一次。

    展开全文
  • react useEffect

    2021-03-04 15:30:32
    useEffect 使用: import React, { useState , useEffect } from 'react'; function Example(){ const [ count , setCount ] = useState(0); //---关键代码---------start------- useEffect(()=>{ console....

    useEffect

    使用:

    import React, { useState , useEffect } from 'react';
    function Example(){
        const [ count , setCount ] = useState(0);
        //---关键代码---------start-------
        useEffect(()=>{
            console.log(`useEffect=>You clicked ${count} times`)
        })
        //---关键代码---------end-------
    
        return (
            <div>
                <p>You clicked {count} times</p>
                <button onClick={()=>{setCount(count+1)}}>click me</button>
            </div>
        )
    }
    

    第一次组件渲染和每次组件更新都会执行这个函数

    展开全文
  • useEffect参数

    2021-03-31 21:10:49
    参数 只有第一个参数的情况 function Parents() { //每次通过setState改变state时,Parents都会重新执行,但是返回的state是被修改后的值 ... //和componentDidMount不同的是,state改变每次useEffect都会重新执行

    参数

    只有第一个参数的情况
    function Parents() {
      //每次通过setState改变state时,Parents都会重新执行,但是返回的state是被修改后的值
      const [state, setState] = useState(0);
    
      //没有第二个参数的useEffect
      useEffect(() => {
        console.log("订阅"); //和componentDidMount不同的是,state改变每次useEffect都会重新执行
        
        //和componentsWillUmmount不同的是,首次渲染不执行,第二次渲染会在return之后被执行
        return () => {
          console.log("取消订阅");
        };
      });
    
      console.log("hello");
    
      return (
        <div style={{ width: "500px", height: "500px", backgroundColor: "red" }}>
          父组件{state} <button onClick={() => setState(state + 1)}>点击+1</button>{" "}
          <Son></Son>
        </div>
      );
    }
    

    初次渲染
    在这里插入图片描述
    点击按钮触发二次渲染
    在这里插入图片描述

    两个参数都有的情况
    function Parents() {
      //每次通过setState改变state时,Parents都会重新执行,但是返回的state是被修改后的值
      const [state, setState] = useState(0);
      const [count, setCount] = useState(0);
      //第二个参数的useEffect
      useEffect(() => {
        console.log("订阅"); //componentDidMount
    
        //当有了第二个参数的时候,才完全类似于componentsWillUmmount
        return () => {
          console.log("取消订阅");
        };
      }, [count]);  //数组中所依赖的值发生了改变,useEffect才会被重新执行,componentDidUpdate
    
      console.log("hello");
    
      return (
        <div style={{ width: "500px", height: "500px", backgroundColor: "red" }}>
          父组件{state} <button onClick={() => setState(state + 1)}>点击+1</button>
          <Son></Son>
        </div>
      );
    }
    

    在这里插入图片描述

    父子组件

    只有一个参数

    每次修改父组件的state,触发父组件重新渲染
    在这里插入图片描述

    两个参数

    每次修改父组件的state,触发父组件重新渲染
    在这里插入图片描述

    展开全文
  • useEffect使用指南

    万次阅读 多人点赞 2019-07-02 16:27:26
    所以决定总结一下Hooks的使用经验,从useEffect开始。useEffect用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作。这里以数据请求为例,来深入介绍useEffect的用法。 最基本的使用 首先,举一...

    最近在写一些React的应用,用上了最新的Hooks。Hooks好用,但是对于刚上手Hooks的小伙伴来说,坑也挺多的。所以决定总结一下Hooks的使用经验,从useEffect开始。useEffect用于处理组件中的effect,通常用于请求数据,事件处理,订阅等相关操作。这里以数据请求为例,来深入介绍useEffect的用法。

    最基本的使用

    首先,举一个简单的例子:

    import React, { useState } from 'react';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
    
      return (
        <ul>
          {data.hits.map(item => (
            <li key={item.objectID}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      );
    }
    
    export default App;
    

    App组件显示了一个项目列表,状态和状态更新函数来自与useState这个hooks,通过调用useState,来创建App组件的内部状态。初始状态是一个object,其中的hits为一个空数组,目前还没有请求后端的接口。

    为了获取后端提供的数据,接下来将使用axios来发起请求,同样也可以使用fetch,这里会使用useEffect来隔离副作用。

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
    
      useEffect(async () => {
        const result = await axios(
          'http://localhost/api/v1/search?query=redux',
        );
    
        setData(result.data);
      });
    
      return (
        <ul>
          {data.hits.map(item => (
            <li key={item.objectID}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      );
    }
    
    export default App;
    

    在useEffect中,不仅会请求后端的数据,还会通过调用setData来更新本地的状态,这样会触发view的更新。

    但是,运行这个程序的时候,会出现无限循环的情况。useEffect在组件mount时执行,但也会在组件更新时执行。因为我们在每次请求数据之后都会设置本地的状态,所以组件会更新,因此useEffect会再次执行,因此出现了无限循环的情况。我们只想在组件mount时请求数据。我们可以传递一个空数组作为useEffect的第二个参数,这样就能避免在组件更新执行useEffect,只会在组件mount时执行。

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
    
      useEffect(async () => {
        const result = await axios(
          'http://localhost/api/v1/search?query=redux',
        );
    
        setData(result.data);
      }, []);
    
      return (
        <ul>
          {data.hits.map(item => (
            <li key={item.objectID}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      );
    }
    
    export default App;
    

    useEffect的第二个参数可用于定义其依赖的所有变量。如果其中一个变量发生变化,则useEffect会再次运行。如果包含变量的数组为空,则在更新组件时useEffect不会再执行,因为它不会监听任何变量的变更。

    还有最后一个问题。在代码中,我们使用async / await从第三方API获取数据。如果你对async/await熟悉的话,你会知道,每个async函数都会默认返回一个隐式的promise。但是,useEffect不应该返回任何内容。这就是为什么会在控制台日志中看到以下警告:

    Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => …) are not supported, but you can call an async function inside an effect

    这就是为什么不能直接在useEffect中使用async函数,因此,我们可以不直接调用async函数,而是像下面这样:

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            'http://localhost/api/v1/search?query=redux',
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, []);
    
      return (
        <ul>
          {data.hits.map(item => (
            <li key={item.objectID}>
              <a href={item.url}>{item.title}</a>
            </li>
          ))}
        </ul>
      );
    }
    
    export default App;
    

    响应更新

    上面的例子中,我们实现了再组件mount时请求数据。但是很多情况下,我们需要响应用户的输入,然后再请求。这个时候我们会引入一个input框,监听query值的变化:

    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            'http://localhost/api/v1/search?query=redux',
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, []);
    
      return (
        <Fragment>
          <input
            type="text"
            value={query}
            onChange={event => setQuery(event.target.value)}
          />
          <ul>
            {data.hits.map(item => (
              <li key={item.objectID}>
                <a href={item.url}>{item.title}</a>
              </li>
            ))}
          </ul>
        </Fragment>
      );
    }
    
    export default App;
    

    有个query值,已经更新query的逻辑,还需要将这个query值传递给后台,这个操作会在useEffect中进行:

    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            `http://localhost/api/v1/search?query=${query}`,
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, []);
    
      return (
        ...
      );
    }
    
    export default App;
    

    前面我们说了,目前的useEffect只会在组件mount时执行,并且useEffect的第二个参数是依赖的变量,一旦这个依赖的变量变动,useEffect就会重新执行,所以我们需要添加query为useEffect的依赖:

    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            `http://localhost/api/v1/search?query=${query}`,
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, [query]);
    
      return (
        ...
      );
    }
    
    export default App;
    

    一旦更改了query值,就可以重新获取数据。但这会带来另一个问题:query的任何一次变动都会请求后端,这样会带来比较大的访问压力。这个时候我们需要引入一个按钮,点击这个按钮再发起请求

    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
      const [search, setSearch] = useState('');
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            `http://localhost/api/v1/search?query=${query}`,
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, [query]);
    
      return (
        <Fragment>
          <input
            type="text"
            value={query}
            onChange={event => setQuery(event.target.value)}
          />
          <button type="button" onClick={() => setSearch(query)}>
            Search
          </button>
    
          <ul>
            {data.hits.map(item => (
              <li key={item.objectID}>
                <a href={item.url}>{item.title}</a>
              </li>
            ))}
          </ul>
        </Fragment>
      );
    }
    

    可以看到上面我们添加了一个新的按钮,然后创建新的组件state:search。每次点击按钮时,会把search的值设置为query,这个时候我们需要修改useEffect中的依赖项为search,这样每次点击按钮,search值变更,useEffect就会重新执行,避免不必要的变更:

    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
      const [search, setSearch] = useState('redux');
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(
            `http://localhost/api/v1/search?query=${search}`,
          );
    
          setData(result.data);
        };
    
        fetchData();
      }, [search]);
    
      return (
        ...
      );
    }
    
    export default App;
    

    此外,search state的初始状态设置为与query state 相同的状态,因为组件首先会在mount时获取数据。所以简单点,直接将的要请求的后端URL设置为search state的初始值。

    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
      const [url, setUrl] = useState(
        'http://localhost/api/v1/search?query=redux',
      );
    
      useEffect(() => {
        const fetchData = async () => {
          const result = await axios(url);
    
          setData(result.data);
        };
    
        fetchData();
      }, [url]);
    
      return (
        <Fragment>
          <input
            type="text"
            value={query}
            onChange={event => setQuery(event.target.value)}
          />
          <button
            type="button"
            onClick={() =>
              setUrl(`http://localhost/api/v1/search?query=${query}`)
            }
          >
            Search
          </button>
        <ul>
            {data.hits.map(item => (
              <li key={item.objectID}>
                <a href={item.url}>{item.title}</a>
              </li>
            ))}
          </ul>
        </Fragment>
      );
    }
    

     

    如何处理Loading和Error

    良好的用户体验是需要在请求后端数据,数据还没有返回时展现loading的状态,因此,我们还需要添加一个loading的state

    import React, { Fragment, useState, useEffect } from 'react';
    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
      const [url, setUrl] = useState(
        'http://hn.algolia.com/api/v1/search?query=redux',
      );
      const [isLoading, setIsLoading] = useState(false);
    
      useEffect(() => {
        const fetchData = async () => {
          setIsLoading(true);
    
          const result = await axios(url);
    
          setData(result.data);
          setIsLoading(false);
        };
    
        fetchData();
      }, [url]);
      return (
        <Fragment>
          <input
            type="text"
            value={query}
            onChange={event => setQuery(event.target.value)}
          />
          <button
            type="button"
            onClick={() =>
              setUrl(`http://localhost/api/v1/search?query=${query}`)
            }
          >
            Search
          </button>
    
          {isLoading ? (
            <div>Loading ...</div>
          ) : (
            <ul>
              {data.hits.map(item => (
                <li key={item.objectID}>
                  <a href={item.url}>{item.title}</a>
                </li>
              ))}
            </ul>
          )}
        </Fragment>
      );
    }
    
    export default App;
    

    在useEffect中,请求数据前将loading置为true,在请求完成后,将loading置为false。我们可以看到useEffect的依赖数据中并没有添加loading,这是因为,我们不需要再loading变更时重新调用useEffect。请记住:只有某个变量更新后,需要重新执行useEffect的情况,才需要将该变量添加到useEffect的依赖数组中。

    loading处理完成后,还需要处理错误,这里的逻辑是一样的,使用useState来创建一个新的state,然后在useEffect中特定的位置来更新这个state。由于我们使用了async/await,可以使用一个大大的try-catch:

    import React, { Fragment, useState, useEffect } from 'react';
    import axios from 'axios';
    
    function App() {
      const [data, setData] = useState({ hits: [] });
      const [query, setQuery] = useState('redux');
      const [url, setUrl] = useState(
        'http://localhost/api/v1/search?query=redux',
      );
      const [isLoading, setIsLoading] = useState(false);
      const [isError, setIsError] = useState(false);
    
      useEffect(() => {
        const fetchData = async () => {
          setIsError(false);
          setIsLoading(true);
    
          try {
            const result = await axios(url);
    
            setData(result.data);
          } catch (error) {
            setIsError(true);
          }
    
          setIsLoading(false);
        };
    
        fetchData();
      }, [url]);
      return (
        <Fragment>
          <input
            type="text"
            value={query}
            onChange={event => setQuery(event.target.value)}
          />
          <button
            type="button"
            onClick={() =>
              setUrl(`http://localhost/api/v1/search?query=${query}`)
            }
          >
            Search
          </button>
    
          {isError && <div>Something went wrong ...</div>}
    
          {isLoading ? (
            <div>Loading ...</div>
          ) : (
            <ul>
              {data.hits.map(item => (
                <li key={item.objectID}>
                  <a href={item.url}>{item.title}</a>
                </li>
              ))}
            </ul>
          )}
        </Fragment>
      );
    }
    
    export default App;
    

    每次useEffect执行时,将会重置error;在出现错误的时候,将error置为true;在正常请求完成后,将error置为false。

    处理表单

    通常,我们不仅会用到上面的输入框和按钮,更多的时候是一张表单,所以也可以在表单中使用useEffect来处理数据请求,逻辑是相同的:

    function App() {
      ...
    
      return (
        <Fragment>
          <form
            onSubmit={() =>
              setUrl(`http://localhost/api/v1/search?query=${query}`)
            }
          >
            <input
              type="text"
              value={query}
              onChange={event => setQuery(event.target.value)}
            />
            <button type="submit">Search</button>
          </form>
    
          {isError && <div>Something went wrong ...</div>}
    
          ...
        </Fragment>
      );
    }
    

    上面的例子中,提交表单的时候,会触发页面刷新;就像通常的做法那样,还需要阻止默认事件,来阻止页面的刷新。

    function App() {
      ...
    
      const doFetch = () => {
        setUrl(`http://localhost/api/v1/search?query=${query}`);
      };
    
      return (
        <Fragment>
          <form onSubmit={event => {
            doFetch();
    
            event.preventDefault();
          }}>
            <input
              type="text"
              value={query}
              onChange={event => setQuery(event.target.value)}
            />
            <button type="submit">Search</button>
          </form>
    
          {isError && <div>Something went wrong ...</div>}
    
          ...
        </Fragment>
      );
    }
    

    自定义hooks

    我们可以看到上面的组件,添加了一系列hooks和逻辑之后,已经变得非常的庞大。而hooks的一个非常的优势,就是能够很方便的提取自定义的hooks。这个时候,我们就能把上面的一大堆逻辑抽取到一个单独的hooks中,方便复用和解耦:

    function useFetchApi = () => {
      const [data, setData] = useState({ hits: [] });
      const [url, setUrl] = useState(
        'http://localhost/api/v1/search?query=redux',
      );
      const [isLoading, setIsLoading] = useState(false);
      const [isError, setIsError] = useState(false);
    
      useEffect(() => {
        const fetchData = async () => {
          setIsError(false);
          setIsLoading(true);
    
          try {
            const result = await axios(url);
    
            setData(result.data);
          } catch (error) {
            setIsError(true);
          }
    
          setIsLoading(false);
        };
    
        fetchData();
      }, [url]);
    
      const doFetch = () => {
        setUrl(`http://localhost/api/v1/search?query=${query}`);
      };
    
      return { data, isLoading, isError, doFetch };
    }
    

    在自定义的hooks抽离完成后,引入到组件中

    function App() {
      const [query, setQuery] = useState('redux');
      const { data, isLoading, isError, doFetch } = useHackerNewsApi();
    
      return (
        <Fragment>
          ...
        </Fragment>
      );
    }
    

    然后我们需要在form组件中设定初始的后端URL

    const useHackerNewsApi = () => {
      ...
    
      useEffect(
        ...
      );
    
      const doFetch = url => {
        setUrl(url);
      };
    
      return { data, isLoading, isError, doFetch };
    };
    
    function App() {
      const [query, setQuery] = useState('redux');
      const { data, isLoading, isError, doFetch } = useHackerNewsApi();
    
      return (
        <Fragment>
          <form
            onSubmit={event => {
              doFetch(
                `http://localhost/api/v1/search?query=${query}`,
              );
    
              event.preventDefault();
            }}
          >
            <input
              type="text"
              value={query}
              onChange={event => setQuery(event.target.value)}
            />
            <button type="submit">Search</button>
          </form>
    
          ...
        </Fragment>
      );
    }
    

    使用useReducer整合逻辑

    到目前为止,我们已经使用了各种state hooks来管理数据,包括loading、error、data等状态。但是我们可以看到,这三个有关联的状态确是分散的,它们通过分离的useState来创建,为了有关联的状态整合到一起,我们需要用到useReducer。

    如果你写过redux,那么将会对useReducer非常的熟悉,可以把它理解为一个轻量额redux。useReducer 返回一个状态对象和一个可以改变状态对象的dispatch函数。跟redux类似的,dispatch函数接受action作为参数,action包含type和payload属性。我们看一个简单的例子吧:

    import React, {
      Fragment,
      useState,
      useEffect,
      useReducer,
    } from 'react';
    import axios from 'axios';
    
    const dataFetchReducer = (state, action) => {
      ...
    };
    
    const useDataApi = (initialUrl, initialData) => {
      const [url, setUrl] = useState(initialUrl);
    
      const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
      });
    
      ...
    };
    

    useReducer将reducer函数和初始状态对象作为参数。在我们的例子中,data,loading和error状态的初始值与useState创建时一致,但它们已经整合到一个由useReducer创建对象,而不是多个useState创建的状态。

    const dataFetchReducer = (state, action) => {
      ...
    };
    
    const useDataApi = (initialUrl, initialData) => {
      const [url, setUrl] = useState(initialUrl);
    
      const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
      });
    
      useEffect(() => {
        const fetchData = async () => {
          dispatch({ type: 'FETCH_INIT' });
    
          try {
            const result = await axios(url);
    
            dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
          } catch (error) {
            dispatch({ type: 'FETCH_FAILURE' });
          }
        };
    
        fetchData();
      }, [url]);
    
      ...
    };
    

    在获取数据时,可以调用dispatch函数,将信息发送给reducer。使用dispatch函数发送的参数为object,具有type属性和可选payload的属性。type属性告诉reducer需要应用哪个状态转换,并且reducer可以使用payload来创建新的状态。在这里,我们只有三个状态转换:发起请求,请求成功,请求失败。

    在自定义hooks的末尾,state像以前一样返回,但是因为我们拿到的是一个状态对象,而不是以前那种分离的状态,所以需要将状态对象解构之后再返回。这样,调用useDataApi自定义hooks的人仍然可以访问dataisLoading 和 isError这三个状态。

    const useDataApi = (initialUrl, initialData) => {
      const [url, setUrl] = useState(initialUrl);
    
      const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
      });
    
      ...
    
      const doFetch = url => {
        setUrl(url);
      };
    
      return { ...state, doFetch };
    }; 
    

    接下来添加reducer函数的实现。它需要三种不同的状态转换FETCH_INITFETCH_SUCCESSFETCH_FAILURE。每个状态转换都需要返回一个新的状态对象。让我们看看如何使用switch case语句实现它:

      switch (action.type) {
        case 'FETCH_INIT':
          return {
            ...state,
            isLoading: true,
            isError: false
          };
        case 'FETCH_SUCCESS':
          return {
            ...state,
            isLoading: false,
            isError: false,
            data: action.payload,
          };
        case 'FETCH_FAILURE':
          return {
            ...state,
            isLoading: false,
            isError: true,
          };
        default:
          throw new Error();
      }
    };
    

    取消数据请求

    React中的一种很常见的问题是:如果在组件中发送一个请求,在请求还没有返回的时候卸载了组件,这个时候还会尝试设置这个状态,会报错。我们需要在hooks中处理这种情况,可以看下是怎样处理的:

    const useDataApi = (initialUrl, initialData) => {
      const [url, setUrl] = useState(initialUrl);
    
      const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
      });
    
      useEffect(() => {
        let didCancel = false;
    
        const fetchData = async () => {
          dispatch({ type: 'FETCH_INIT' });
    
          try {
            const result = await axios(url);
    
            if (!didCancel) {
              dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
            }
          } catch (error) {
            if (!didCancel) {
              dispatch({ type: 'FETCH_FAILURE' });
            }
          }
        };
      fetchData();
    
        return () => {
          didCancel = true;
        };
      }, [url]);
    
      const doFetch = url => {
        setUrl(url);
      };
    
      return { ...state, doFetch };
    };
    

    我们可以看到这里新增了一个didCancel变量,如果这个变量为true,不会再发送dispatch,也不会再执行设置状态这个动作。这里我们在useEffe的返回函数中将didCancel置为true,在卸载组件时会自动调用这段逻辑。也就避免了再卸载的组件上设置状态。

    源代码:

    https://github.com/anymost/hooks-demo/blob/master/src/page/Effect.js​github.com

    原文https://zhuanlan.zhihu.com/p/65773322

    展开全文
  • useState useEffect

    2020-06-11 16:00:42
    hook import React, { useState } from ‘react’ ...import React, { useEffect } from ‘react’ useEffect(() => { })[a,b] // 当ab改变时才会执行。如果不传的话相当于componentDidUpdate。 ...
  • useEffect vs useLayoutEffect

    2020-11-28 04:13:32
    <p>From <a href="https://kentcdodds.com/blog/useeffect-vs-uselayouteffect">this article</a> about the difference: <h3><code>useEffect</code></h3> <p>...this runs after react renders your component ...
  • react hooks useEffect

    2020-02-18 08:05:31
    useEffect代替生命周期函数componentDidMount页面加载和componentDidUpdate页面更新 //useEffect代替生命周期函数 componentDidMount页面加载和componentDidUpdate页面更新 import React, { useState,useEffect }...
  • useEffect is synchronous?

    2020-11-29 17:33:13
    let { component, useState, useEffect, State } = await import("haunted") let state = new State(() => { update(); }); function update() { state.run(() => { ...
  • useEffect学习随笔

    2020-10-21 17:29:48
    因此也借此机会,学习了一波useEffect的使用,记录随笔以备日后查阅 当我们写一个函数,我们希望的是这个函数返回的是一个页面来进行显示 那么其余和数据计算以及显示的操作,我们把其称为副作用 比如我们想显示一个...
  • This seems to be because the last <code>useEffect</code> hook inside the custom <code>useTokenTracker</code> hook will run whenever the <code>tokens</code> object changes, even if it does not <em>...
  • 自定义钩子来调试useEffect
  • <div><p>There are multiple useEffect hooks used and both of the useEffect hooks are going to call for only once so they can merge into the single useEffect hook.</p><p>该提问来源于开源项目:...
  • useEffect使用规范

    2020-09-07 14:10:48
    使用 Effect Hook Hook 是 React 16.8 的新增特性。...import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to component
  • useEffect 完整指南

    2020-04-19 16:58:57
    ????:https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/ 收藏???? 未完待续…I’m studying.????
  • hooks之useEffect

    2020-04-01 22:29:46
    import React, { Component, useState, useEffect } from 'react' // 类写法 class App2 extends Component { constructor() { super() this.state = { count: 0, size: { width: docum...
  • Hooks useState useEffect

    2020-04-21 13:11:41
    import React, { useState,useEffect } from 'react' function Hook() { 数组第一项相当于state中的数据 数组第二项是改变当前数组第一项的setstate的方法 setName('老朱')直接传入修改的数据 useState() 里面...
  • useLayoutEffect 等同于useEffect, 但它会在所有dom改变之后同步触发,使用useLayoutEffect可以读取dom的布局并且同步重新渲染。赶在浏览器绘制之前,useLayoutEffect内部的更新将同步刷新; 如果你使用类组件,...
  • <p>There currently is no better abstraction, I see useEffect used in asyncTask? <p>I sort of struggle to see the usefulness of all these hook libraries if they cannot be used in event handlers. <p>I ...
  • Problem using with useEffect

    2020-12-25 22:54:09
    The idea is simply to display whether the component is loading or not, with the action for the background work being dispatched in a useEffect hook. However, after the work is done and the state gets...
  • useEffect与useLayoutEffect

    千次阅读 2019-06-18 19:01:48
    useEffect与useLayoutEffect React Hook让无狀态组件拥有了许多只有有狀态组件的能力,如自更新能力(setState,使用useState),访问ref(使用useRef或useImperativeMethods),访问context(使用useContext),使用...
  • ReactHook-useEffect

    2020-11-04 00:48:07
    useEffect 作用: 推迟代码执行 渲染完成之后再执行,常用于 数据读取 完成移除 定时器、监听 第二个参数来模拟生命周期。 useEffect存在一种bail out(保释)机制: 当你尝试设置相同的状态,不会渲染,也...
  • react hook - useEffect详解

    千次阅读 2020-07-15 15:59:54
    useEffect不传递第二个参数会导致每次渲染都会运行useEffect。然后,当它运行时,它获取数据并更新状态。然后,一旦状态更新,组件将重新呈现,这将再次触发useEffect,这就是问题所在。 2、传递空数组 3、传递count...
  • useEffect使用的介绍

    2020-04-29 16:24:41
    如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMount,componentDidUpdate 和 componentWillUnmount 这三个函数的组合。 使用一个 componentDidMount 的功能 function Demo ...
  • 细烤 useEffect
  • It is because of <code>useEffect</code> missing <code>handler</code> as a dependency. For example: <pre><code>js useNavigationButtonPress( () => deleteSomething(somethingId), // it will work ...
  • useEffect 介绍 useEffect时reactHook中最重要,最常用的hook之一。 useEffect相当于react中的什么生命周期呢? 这个问题在react官网中有过介绍,在使用的过程中,容易被忽略,在面试的时候却经常被问及,(面试造...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,566
精华内容 1,026
热门标签
关键字:

useeffect