Next.js正在获取要在组件中显示的Json

xdnvmnnf  于 2022-11-19  发布在  其他
关注(0)|答案(1)|浏览(209)

我尝试将MainMenu和getStaticProps函数从同一个页面(index.js)中分离出来,并将其分解为多个组件。下面是运行良好的index.js页面。

#index.js

import Link from 'next/link';

function MainMenu({ menuLists }) {
  return (
   <div>
      {menuLists.map(menuItem => (
        <div>
          <Link href={menuItem.absolute}><a>{menuItem.title}</a></Link>

          {menuItem.below && menuItem.below.map(childItem => (
            <div>
              <Link href={childItem.absolute}><a>{childItem.title}</a></Link>
            </div>
          ))}
        </div>
      ))}
  </div>
  )
}
export async function getStaticProps() {

  const response = await fetch('http://localhost:8888/api/menu_items/main');
  const menuLists = await response.json();
  
  return {
    props: {
      menuLists: menuLists,
    },
  }
}
export default MainMenu

我已经使用以下代码在lib目录中创建了fetch-mainmenu.js。

#fetch-mainmenu.js

export async function loadMainMenu() {
    
    const response = await fetch('http://localhost:8888/api/menu_items/main')
    const menuLists = await response.json()
  
    return {
        props: {
          menuLists: menuLists,
        },
      }
  }

然后我创建了sidebar.js来显示json文件中的菜单系统。sidebar.js文件可以正常工作,因为硬编码的菜单可以显示。

# sidebar.js

import Link from 'next/link'
import styles from './sidebar.module.css'
import { loadMainMenu } from '../lib/fetch-mainmenu'

export default function Sidebar( { menuLists } ) {

const menus = loadMainMenu()

  return (
  
    <nav className={styles.nav}>
      <input className={styles.input} placeholder="Search..." />
      <Link href="/">
        
        <a>Home</a>
      </Link>
      <Link href="/about">
        <a>About</a>
      </Link>
      <Link href="/contact">
        <a>Contact</a>
      </Link>
    </nav>
  )
}

出现以下错误“TypeError:无法获取””。使用组件完成此操作的最佳方法是什么。

oxcyiej7

oxcyiej71#

溶液

1.支柱钻孔

简单,把getStaticProps()的所有数据都发下来,这是目前最安全的选择,但可能会产生一些多余的道具。

// I've omitted fetch().json() to ease the reading. just assume it's a proper code.

const MainMenuComponent = ({menuLists}) => {
  return <div>{menuLists}</div>
}

const MainPage = ({menuLists}) => {
  return <MainMenuComponent menuLists={menuLists} />
}

export async function getStaticProps() {

  const req = await fetch('...');
  
  return {
    props: {
      menuLists: req,
    },
  }
}
export default MainPage

2.React使用效果

React组件在呈现代码中不能有异步代码。这在类组件中是很明显的,但在功能组件中就很难说了

// I've omitted fetch().json() to ease the reading. just assume it's a proper code.

// class component
class SampleComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: {} };
  }
  async getData() {
    // ✅ this works
    const data = await fetch('...');
    // data has to be put in state because it's asynchronous.
    this.setState({ ...this.state, data });
  }
  componentDidMount() {
    this.getData();
  }
  render() {
    // ❌ this can't happen here because render is synchronous
    await fetch('...');
    // use state to display asynchronous data.
    return <h1>Hello, {JSON.stringify(this.state.data)}</h1>;
  }
}

// functional component
function SampleComponent = () => {
  // everything outside `useEffect, useLayoutEffect` is mostly assumed as render function.
  // ❌ thus, this does not work here
  await fetch('...');

  const [data, setData] = useState({});
  useEffect(async () => {
    // everything inside here treated as componentDidMount()
    // not the exact same thing though.
    // ✅ this works!
    setData(await fetch('...'))
  }, []);

  return <h1>Hello, {JSON.stringify(data)}</h1>
}

警告如果页面中有getStaticProps,这意味着组件也必须同步。如果呈现的组件在很短的时间内(几分之一秒)更改了其内容,那么它可能会得到再水化错误。它需要用dynamic() Package ,以便Next.js在呈现服务器端和再水化组件时可以忽略该组件。请参阅Next.js official document on Dynamic Import

它确实工作,但代码似乎很长。

3. TanStack查询(或React-Query)或使用SWR

有一些不错的第三方库可以帮助编写react组件中的异步数据获取代码; TanStack QuerySWR是最著名的。这些库还实现了缓存和重新验证。它可以帮助处理由于异步请求而调用的复杂问题。

// example code from useSWR
import useSWR from 'swr'

function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return <div>hello {data.name}!</div>
}

4.使用上下文进行状态管理

大多数情况下,Query-SWR解决方案可以轻松处理,但如果应用程序变得足够大,则可能需要同步数据。
在这种情况下,获取服务器代码中的数据,并与中央状态管理库(也称为存储库)共享数据。一个很好的例子是this github repo of Zustand + Next.js。也可以使用裸React.Context。
但是,这种方法以后会变得非常复杂,也许不适合一个没有经验的团队;这基本上类似于构建另一个像后端一样大的复杂层。这就是为什么现在的趋势是转向Query-SWR解决方案。尽管如此,在某些情况下,这还是很方便的。

import { useStore } from "../lib/store";
const SampleComponent = () => {
  const { data } = useStore();
  return <div>{JSON.stringify(data)}</div>
}

const MainPage() {
  return <SampleComponent />
}

export async function getStaticProps() {
  // refer to the github repo for this store structure
  const zustandStore = initializeStore();
  // this is a POC. the actual code could be different.
  // store data is updated, and can be used globally in other components in a synchronized state.
  const data = await useStore.setData(await fetch('...'));

  return {
    props: {
      initialZustandState: JSON.parse(JSON.stringify({ ...zustandStore.getState(), data })),
    },
  };
}

5.服务器端组件

随着React 18 server side component的出现,Next.js也在开发Next.js Server Components
这个实现可能是最接近问题中代码的实现。然而,工作仍在进行中,非常不稳定。
我关注这个方法已经有一年了,但是它的实现一直在不断的变化。在我们得到稳定的版本之前,这个可以等等。

相关问题