最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Confused about passing data between server and client in next.js - Stack Overflow

programmeradmin1浏览0评论

I'm having trouble understanding the correct way of handling data exchange between server-side and client-side ponents in NextJS 13.

I'm trying to understand this by creating the simplest scenario possible. I have these two functions that simply read and write JSON files on the server:

import fs from 'fs'

export const saveData = async (data) => {
  const jsonData = JSON.stringify(data)
  try {
    await fs.promises.writeFile('data/data.json', jsonData)
  } catch (err) {
    console.log('Error', err)
  }
}

export const getData = async () => {
  try {
    const jsonData = await fs.promises.readFile('data/data.json')
    const data = JSON.parse(jsonData)
    return data

  } catch (err) {
    console.log('Error', err)
    return null
  }
}

A React ponent that displays the data:

export const SomeComponent = ({ data }) => <p>{data.someKey}</p>

And an interactive React ponent that gets user input:

'use client'
import { useState } from 'react'

export default function Input({ handleInput }) {
  const [value, setValue] = useState()

  return (
    <div>
      <input type="text" onChange={(e) => setValue(e.target.value)}/>
      <button onClick={() => handleInput(value)}>Save</button>
    </div>
  )
}

If I create a page function to get the data and handle saving new data, I cannot pass the handler to the Input ponent, because it's a client-side ponent.

import { SomeComponent } from './ponents/ponent'
import { getData, saveData } from './data'
import Input from './ponents/input'

export default async function Home() {
  const data = await getData()

  const handleInput = (data) => {
    saveData(data)
  }

  return (
    <div>
      <SomeComponent data={data} />
      {/* Error: */}
      <Input handleInput={handleInput}/>
    </div>
  )
}

How, then, is passing data between the client and the server supposed to be handled in this example?

I'm having trouble understanding the correct way of handling data exchange between server-side and client-side ponents in NextJS 13.

I'm trying to understand this by creating the simplest scenario possible. I have these two functions that simply read and write JSON files on the server:

import fs from 'fs'

export const saveData = async (data) => {
  const jsonData = JSON.stringify(data)
  try {
    await fs.promises.writeFile('data/data.json', jsonData)
  } catch (err) {
    console.log('Error', err)
  }
}

export const getData = async () => {
  try {
    const jsonData = await fs.promises.readFile('data/data.json')
    const data = JSON.parse(jsonData)
    return data

  } catch (err) {
    console.log('Error', err)
    return null
  }
}

A React ponent that displays the data:

export const SomeComponent = ({ data }) => <p>{data.someKey}</p>

And an interactive React ponent that gets user input:

'use client'
import { useState } from 'react'

export default function Input({ handleInput }) {
  const [value, setValue] = useState()

  return (
    <div>
      <input type="text" onChange={(e) => setValue(e.target.value)}/>
      <button onClick={() => handleInput(value)}>Save</button>
    </div>
  )
}

If I create a page function to get the data and handle saving new data, I cannot pass the handler to the Input ponent, because it's a client-side ponent.

import { SomeComponent } from './ponents/ponent'
import { getData, saveData } from './data'
import Input from './ponents/input'

export default async function Home() {
  const data = await getData()

  const handleInput = (data) => {
    saveData(data)
  }

  return (
    <div>
      <SomeComponent data={data} />
      {/* Error: */}
      <Input handleInput={handleInput}/>
    </div>
  )
}

How, then, is passing data between the client and the server supposed to be handled in this example?

Share Improve this question edited Jun 21, 2023 at 10:33 Nick Parsons 51.1k6 gold badges57 silver badges77 bronze badges asked Jun 21, 2023 at 10:26 CirrocumulusCirrocumulus 6306 silver badges20 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

You basically have two options when it es to this problem:

  1. Option 1: An API that can be called from the client ponent which updates the file and optimistically updating the local state. Probably the more mon approach to this kind of requirement.

  2. Option 2: A server action that which passed to the client ponent in bination with the new useOptimistic hook. Keep in mind that server actions are still in alpha and not remended to use in production yet.

I strongly remend you check the official docs about the limitations and specification of server actions. Here is a simple example what the second option may look like if implemented:

Your server ponent
const onSave = async (update: any) => {
  "use server";
  const { default: fs } = await import("fs"); 
  await fs.writeJSON("./myfile.json", update);
}

async function ServerComponent(): Promise<JSX.Element> {
  const data = await getMyData();
  return <ClientComponent data={data} onSave={onSave} />;
}

The use server directive is used to define the function as a server action. Keep in mind that server actions do not respect sessions by default and the same function is ran for each request.

Your client ponent
function ClientComponent(props: Props): JSX.Element {
  const { data: initialData, onSave } = props;
  
  const [data, setData] = useState(initialData);

  const onUpdate = useCallback(async (update: any) => {
    setData(prev => ({ ...prev, ...update }));
    await onSave(update);
  }, [onSave]);

  return // ...
}

You will have to activate server actions inside your next config file due to their current alpha state, otherwise this example will not work.

发布评论

评论列表(0)

  1. 暂无评论