【问题标题】:React Hooks: setState, when does it actually take effect?React Hooks:setState,什么时候真正生效?
【发布时间】:2020-05-25 14:16:54
【问题描述】:

所以我试图了解 React Hooks 以及如何使用它们。我可以按如下方式在组件内部进行提取:

var [pages,setPages] = useState();
var [page,setPage] = useState();

 async function fetchData() {

  await fetch(`https://myBackend/pages`)
  .then(response => response.json())
  .then(response => {
      setPages(response); 
      console.log(pages[0].title);    
  })
 .then(()=>{

  // AT THIS STAGE, pages IS UNDEFINED

  setPage(pages.filter(singlepage=> {
        return singlepage.url == props.match.params.url;
    }))
 }
  .catch(err => setErrors(err));
 }

useEffect(() => {
  fetchData();
  console.log(pages[0].title);   
  return () => {
      console.log('unmounting...');
  }
  },[]);

我调用我的后端来获取所有页面,这工作正常,就好像我对 pages[0].title 进行编码一样它会呈现。但是当我试图在useEffect 钩子中访问pages 中的特定值时,我要分配page,它给了我pages 未定义的错误。我的控制台日志记录清楚地表明了这一点。

我希望在页面加载之前在“组件安装”上定义 pagepages。所以我的问题是setPages 何时实际设置页面?我是否可以在 useEffect 中同时分配两者并相互依赖?

【问题讨论】:

标签: javascript reactjs react-hooks use-effect


【解决方案1】:

异步操作需要时间。理论上可以通过不确定的时间。因此,无法保证在安装组件之前获取数据。

相反,您需要表现得好像数据可能是未定义的,并具有处理该数据的应用程序状态。

至于在调用setPages 后立即访问 pages 变量,这也将失败,因为 React 实际上是异步运行重新渲染。

即使它同时运行,也有一个叫做 closures 的东西,其中 javascript 在创建函数时会拉入函数周围的所有变量,以便函数始终可以访问这些变量。 React Hooks 通过利用这些闭包来工作,以便仅在组件被渲染/重新渲染时访问变量。出现这种情况的原因是,每次重新渲染,组件中的所有函数都会重新创建,从而创建一个新的闭包。

因此,这意味着您在使用 React 时需要牢记这些概念。

至于您的代码,Dlucidione 设置的结果解决方案是您最好的选择之一,除了设置单独的 useEffect 以在 pages 更改时更新 page

const history = useHistory(); //from react-router-dom
useEffect(() => {
  async function fetchData() {
    return await fetch(`https://myBackend/pages`)
      .then((response) => response.json())
      .then((response) => {
        setPages(response);
      })
      .catch((err) => setErrors(err));
  }
  fetchData();
  return () => {
    console.log('unmounting...');
  };
}, []);

useEffect(() => {
  const url = props.match.params.url;
  if (!pages || !url) return;
  // Using Array#find here because I assume based on the name, you want one page rather than an array
  const page = pages.find((singlepage) => {
    return singlepage.url === url;
  });
  if (!page) {
    // This will change the route if a page isn't found.
    history.push('/404');
  }
  setPage(page);
}, [pages, props.match.params.url, history]);

Redirecthistory.push 的工作方式不同。 Redirect 是声明式导航方式,history.push 是程序式导航方式。

history.push的用法示例:

  if (!page) {
    // This will change the route if a page isn't found.
    history.push('/404');
  }

重要提示,这可以在代码中的任何地方使用,只要您可以将历史记录对象传递到那里。我之前也在 redux thunk 中使用过它。

Redirect 在挂载时不重定向的示例用法:

if(!pages && !page){
 return <Redirect to="/404"/>
}

或者在一些 JSX 中:

<div>
  {!pages && !page && <Redirect to="/404"/>}
</div>

重定向 必须 被渲染,这意味着它只能在组件的 return 语句中使用。

我的理解方式:重定向是基于如果 在安装过程中找到单独的页面,因此 重定向过程也必须在安装过程中检查 在渲染任何东西之前重定向与否。

这是正确的。当 Redirect 本身挂载或更新时,如果条件正确,它将重定向。如果重定向上有 pathfrom 道具(它们是彼此的别名),那么这会将重定向限制为仅在该路径匹配时才起作用。如果路径不匹配,则重定向将不执行任何操作,直到路径更改为匹配(或者它卸载,当然)。

Under the hood, Redirect 只是在 componentDidMount 和 componentDidUpdate 中调用 history.pushhistory.replace(通过 Lifecycle 组件),所以请随意使用。

【讨论】:

  • 谢谢,这澄清了一些事情,我想我只需要注意这些事情。
  • 没错。想象一下,您的连接速度非常慢,下载一点点数据可能需要一个小时。实际上useEffect实际上是在初始渲染后触发的,所以效果再快,你还没有数据。
  • 根据页面是否存在有条件地呈现您的重定向。所以,{pages &amp;&amp; !page &amp;&amp; &lt;Redirect to="/notFound"/&gt;}
  • @yahms23 我已经添加了 useHistory 和我在这个答案上设置的页面效果,但如果你愿意,你可以设置第二个效果。
  • @yahms23,我已经添加了更多详细信息。你的理解很到位:)
【解决方案2】:
    useEffect(() => {
      const fetchData = async () => {
    try {
      // Make a first request
      const result = await axios.get(`firstUrl`);
      setPages(result);
      // here you can use result or pages to do other operation
      setPage(result.filter(singlepage=> {
      return singlepage.url == props.match.params.url;
      or 
      setPage(pages.filter(singlepage=> {
      return singlepage.url == props.match.params.url;
}))
    } catch (e) {
      // Handle error here
    }
  };

  fetchData();
}, []);

【讨论】:

  • pages 不会是最新的,即使是 await
  • 当你使用 await 调用的结果时怎么样?
  • 它会起作用,但它没有解释为什么它对 OP 不起作用。
  • 确实,如果你能提供一把小提琴或钢笔来展示你的情况如何
猜你喜欢
  • 2015-06-04
  • 1970-01-01
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-28
  • 2015-10-10
  • 2013-05-09
相关资源
最近更新 更多