添加设置状态更改会导致React中出现无限循环

时间:2019-09-26 13:15:53

标签: reactjs gatsby

我正在尝试使用gatsby(反应)和Fuse.js创建离线模糊搜索,并且遇到了使用setState存储“搜索”字词的问题。

我收到以下错误: 重新渲染过多。 React限制了渲染次数以防止无限循环。

我不确定如何保存新状态(下面的代码)

 const [posts, setPosts] = useState(null)
    useEffect(() => {
        fetch("/index.json")
            .then(response => response.json())
            .then(function(data) {
                setPosts(data.data.allContentfulPost.edges)
            })
    }, [])

    if (posts) {
        var list = posts //returns 326 items
        var options = {
            shouldSort: true,
            threshold: 0.6,
            location: 0,
            distance: 100,
            maxPatternLength: 32,
            minMatchCharLength: 1,
            keys: ["node.title", "node.meta"],
        }
        var fuse = new Fuse(list, options)
        var results = fuse.search("marketing") //returns 11 items
        setPosts(results) //causes infinite loop
    }

2 个答案:

答案 0 :(得分:0)

除了极少数的用例,您不应该在组件render方法中直接调用setState,如果这样做,则需要谨慎选择正确的条件。

通常情况是这样,如果您的状态取决于提供给组件的道具。基于类的组件生命周期方法称为getDerivedStateFromProps。您不需要这里。

您似乎正在尝试缩小API端点的结果。可以在调用setPosts之前在fetch回调中完成转换:

useEffect(() => {
    fetch("/index.json")
        .then(response => response.json())
        .then(function(data) {
            const allPosts = data.data.allContentfulPost.edges;
            const options = {
                shouldSort: true,
                threshold: 0.6,
                location: 0,
                distance: 100,
                maxPatternLength: 32,
                minMatchCharLength: 1,
                keys: ["node.title", "node.meta"],
            }
            const fuse = new Fuse(allPosts, options)
            const found = fuse.search("marketing")

            setPosts(found);
        })
}, [])

答案 1 :(得分:0)

解决此问题的一种方法是对已过滤的帖子使用另一种状态。并保留原始帖子以备将来使用:

const [posts, setPosts] = useState([]);
const [filteredPosts, setFilteredPosts] = useState([]);

useEffect(() => {
    fetch("/index.json")
        .then(response => response.json())
        .then(function(data) {
            setPosts(data.data.allContentfulPost.edges)
        })
}, []);

useEffect(() => {
  var options = {
      shouldSort: true,
      threshold: 0.6,
      location: 0,
      distance: 100,
      maxPatternLength: 32,
      minMatchCharLength: 1,
      keys: ["node.title", "node.meta"],
  }
  var fuse = new Fuse(posts, options)
  var results = fuse.search("marketing") //returns 11 items
  setFilteredPosts(results) 
}, [posts])