reactjs React,渲染前加载数据

anauzrmj  于 2023-01-04  发布在  React
关注(0)|答案(2)|浏览(233)

我想知道如何在React中渲染之前正确加载数据。
我有一个应用程序,从API获取有关星星大战角色的数据,并将其呈现在页面上。我还想获取下一个角色的数据,然后我想通过点击按钮呈现它。我有一个这个应用程序的例子:
'

function fetchData(count, setState) {
    fetch("https://swapi.dev/api/people/" + count)
    .then(res => res.json())
    .then(data => setState({
        id: count,
        name: data.name,
        birth_year: data.birth_year,
        gender: data.gender
    }))
}

function App() {
    let [data, setData] = React.useState({});
    let [preloadedData, setPreloadedData] = React.useState({});
    let [count, setCount] = React.useState(1);

    React.useEffect(() => {
        if (count === 1) {
            fetchData(count, setData)
            fetchData(count + 1, setPreloadedData);
        }    
        else {
            setData(preloadedData)
            fetchData(count + 1, setPreloadedData);
        }    
    }, [count]);

    console.log(count)
    
    return (
        <main>
            <h1>Starwars character data</h1>
            <p><span>Number:</span> {data.id}</p>
            <p><span>Name:</span> {data.name}</p>
            <p><span>Birth year:</span> {data.birth_year}</p>
            <p><span>Gender:</span> {data.gender}</p>
            <button onClick={() => setCount(count + 1)}>Next character</button>
        </main>        
    )
}

'
我有两个问题:1)这是解决我的问题的正确方法吗,或者可以有更好的实践?2)我想这种方法仍然可能更好,因为console.log被调用了3次,所以我的组件在每次计数状态改变时呈现3次,而且可能更少?
想知道你的意见

sbdsn5lh

sbdsn5lh1#

1)这是解决我问题的正确方法吗
它似乎起作用了,这已经是一个可以接受的解决方案。
当然,它有一些限制,但根据您的实际需求,您可能会暴露他们。特别是,如果用户快速点击几次"下一个字符"按钮(在接收下一个数据之前),您可能会取消同步countdata,如果几个创建的获取请求给出无序的响应,preloadedData也可能不反映count + 1
2)我想这种方式仍然可以更好,因为console.log被调用了3次,所以我的组件在每次计数状态改变时呈现3次,它可以更少?
您不必担心重新呈现(从组件函数被重新执行的意义上说):React更新它的虚拟DOM,但是如果它在输出中没有看到任何变化,那么它就不会触及真正的DOM(因此几乎没有UI影响)。
在您的情况下:

  1. count递增,但模板不受影响=〉无DOM更改
  2. data已更改,这会影响模板值=〉DOM已修改
  3. preloadedData更新,不影响模板=〉无DOM变更
    是否可以有更好的做法?
    我们总是可以改进我们的代码!
    在您的情况下,您可以解决上面提到的限制,同时潜在地提供启用"前一个字符"导航的额外特性,同时仍然重用预加载的数据。
    为此,我们需要累积预加载的数据及其关联的idcount),例如,使用react-use useList钩子:
const [count, setCount] = React.useState(1);
const [list, { updateAt }] = useList([]);

const data = list[count - 1] ?? {}; // index/position is 0-based, whereas count starts at 1, so position is offset by -1 compared to count

function addItem(atPosition) {
  updateAt(atPosition, {}); // Empty data for now
  fetchData(
    atPosition + 1,
    // Store received data at the correct position
    (preloadedData) => updateAt(atPosition, preloadedData)
  );
}

// Initially fill the first 2 items
React.useEffect(() => {
  addItem(0);
  addItem(1);
}, []);

function handleClickNext() {
  const nextCount = count + 1;
  setCount(nextCount);
  // Ensure list always has at least 1 more item than nextCount
  for (let atPosition = list.length; atPosition <= nextCount; atPosition += 1) {
    addItem(atPosition);
  }
}

function handleClickPrevious() {
  if (count > 1) { // Prevent navigating to count <= 0
    setCount(count - 1);
  }
  // No need to update list, necause it should already have been populated when navigating up
}

return (
  <main>
    {/* data display... */}
    <button onClick={handleClickPrevious} disabled={count <= 1}>Previous character</button>
    <button onClick={handleClickNext}>Next character</button>
  </main>
);
nimxete2

nimxete22#

如果您不希望useEffect执行3次,可以传递一个空数组,这样它将只在安装和卸载组件时执行,如下所示:

React.useEffect(() => {
        if (count === 1) {
            fetchData(count, setData)
            fetchData(count + 1, setPreloadedData);
        }    
        else {
            setData(preloadedData)
            fetchData(count + 1, setPreloadedData);
        }    
    }, []); //Look here ;)

在useEffect中获取数据是不错的,但是对于复杂的应用程序来说,使用Redux并用Thunk获取数据要好得多。另一个好的做法是在useEffect结束时返回回调函数来清理数据,如下所示:

React.useEffect(() => {
        if (count === 1) {
            fetchData(count, setData)
            fetchData(count + 1, setPreloadedData);
        }    
        else {
            setData(preloadedData)
            fetchData(count + 1, setPreloadedData);
        }  
       return () => {
          //Clean things here
       }  
    }, []);

我不知道它是否回答了你的问题,但我希望它能有所帮助

相关问题