首页 > 解决方案 > 对 history.push 和 useEffect 反应无限递归

问题描述

我对反应有点陌生,我似乎有鸡和蛋的问题。我想让浏览器 URL 中的查询参数与useState页面中的变量同步。我遇到的问题是,当我useEffect做了一个history.pushthen react 更新触发另一个变量history.push并发生无限递归时。这是我尝试解决的方法,但我必须有重复的代码。一个副本在内部useEffect,另一个副本在外部,useEffect因此我可以在不触发无限递归的情况下使用它。

我以为我读到我可以memoize做点什么,但我不确定。我怎样才能避免这个重复的代码?

import {useState, useEffect} from "react";
import {useHistory, useLocation} from "react-router-dom";

function useQuery() {
  return new URLSearchParams(useLocation().search);
}

export default function Home(props) {
  const history = useHistory();
  const query = useQuery();
  const [something, setSomething] = useState('');
  const [term, setTerm] = useState(query.get('term') === null ? '' : query.get('term'));
  const [urlParams, setUrlParams] = useState(duplicateCode());

  // this duplication of the code below
  function duplicateCode() {
    const params = new URLSearchParams();
    if ( term !== '' ) params.append('term', term);
    return params;
  }

  // this duplication of the code above
  useEffect(() => {
    const params = new URLSearchParams();
    if ( term !== '' ) params.append('term', term);
    setUrlParams(params);
  },[term]);

  // separate useEffect for term and history.push else get infinite recursion
  useEffect(() => {
    history.push('?' + urlParams);
    // simulate API call
    setSomething(urlParams.toString().replace("term=", ""));
  },[history, urlParams]);

  function handleSubmit(event) {
    setTerm(''+Math.random()*100);
    event.preventDefault();
  }
  return (
    <div>
    <p>Term = {something}</p>
    <form onSubmit={handleSubmit}><button>Button</button></form>
    </div>
  );
}

和 App.js 以防万一。

import {React}  from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";

import Home from "./Home";

export default function App(props) {
  return (
    <section className="App">
    <Router>
      <Route exact path="/" component={Home} />
    </Router>
    </section>
  );
};

标签: javascriptreactjs

解决方案


您可以在道具上使用 useEffect 并在那里解析查询字符串。react 路由器会将默认 props 发送到名为 location 的组件并匹配(路径中没有任何复杂的东西,所以没有匹配)

代码:

import { React } from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import queryString from 'query-string'
import { useState, useEffect} from "react";
import { useHistory } from "react-router-dom";

function Home(props) {
  const history = useHistory();
  const [term, setTerm] = useState(props.termIn === null ? "" : props.termIn);

  useEffect(() => {
    const params = queryString.parse(props.location.search);
    if (params.term) {
      setTerm(params.term);
    }
  }, [props]);

  function handleSubmit(event) {
    history.push("/?term=" + (Math.random() * 100));
    event.preventDefault();
  }
  return (
    <div>
      <p>
        Term = {term}
      </p>
      <form onSubmit={handleSubmit}>
        <button>Button</button>
      </form>
    </div>
  );
}
export default function App(props) {
  return (
    <section className="App">
      <Router>
        <Route
          path="/"
          component={Home}
        />
      </Router>
    </section>
  );
}

代码沙箱链接:https ://codesandbox.io/s/so-67231900-hm5od


推荐阅读