You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js14:如何将Server Action的temperature数据传给Server Component

在Next.js 14中传递Server Action数据给Server Component展示

问题场景

需要将create Server Action中获取的temperature值传递给Home Server Component,在首页JSX中展示温度数据。

原代码参考

Home组件(page.tsx)

import Image from "next/image";
import Link from "next/link";
import ProductCard from "./components/ProductCard";
import Search from "./components/Search";

interface latLong {
  latitude: string;
  longitude: string;
}
//server action
export async function create(data: string) {
  console.log(data);
  if (data != "") {
    const apiKey = "123456";
    const geoLocationRes = await fetch(
      `http://api.openweathermap.org/geo/1.0/direct?q=${data}&appid=${apiKey}`
    );
    const geoLocation = await geoLocationRes.json();
    console.log(geoLocation);

    const getLocation: latLong = {
      latitude: geoLocation[0].lat,
      longitude: geoLocation[0].lat,
    };
    const currentWeatherRes = await fetch(
      ` https://api.openweathermap.org/data/2.5/weather?lat=${getLocation.latitude}&lon=${getLocation.longitude}&appid=${apiKey}&units={metric}`
    );
    const currentWeather = await currentWeatherRes.json();
    console.log(currentWeather);

    const temperature = currentWeather.main.temp;
    // console.log(temperature);
    // console.log("input!!");
  } else {
    console.log("no input value");
  }
}
//server component
export default async function Home() {
  return (
    <>
      <h1>Display Temperature here</h1>

      <Search />
    </>
  );
}

Search组件

const Search = () => {
  const [inputVal, setInputVal] = useState("");

  const OnClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault();
    create(inputVal);
  };

  return (
    <>
      <form>
        <input type="text" onChange={(e) => setInputVal(e.target.value)} />
        <button type="button" onClick={OnClick}>
          click
        </button>
      </form>
    </>
  );
}

解决方案

Next.js中Server Component运行在服务器端,Server Action是用户触发的异步操作,以下两种方案可实现数据传递:


方案1:重定向+搜索参数(Server Component友好)

通过重定向将数据携带在URL搜索参数中,Server Component读取参数后展示数据,符合SSR逻辑:

  1. 修改create Server Action:获取温度后重定向回首页,携带城市和温度参数
import { redirect } from 'next/navigation';

interface latLong {
  latitude: string;
  longitude: string;
}

export async function create(formData: FormData) {
  const data = formData.get('city') as string;
  if (data.trim() === "") {
    redirect('/?error=empty-input');
  }

  try {
    const apiKey = "123456";
    // 获取地理坐标
    const geoLocationRes = await fetch(
      `http://api.openweathermap.org/geo/1.0/direct?q=${encodeURIComponent(data)}&appid=${apiKey}`
    );
    const geoLocation = await geoLocationRes.json();

    if (!geoLocation[0]) {
      redirect('/?error=city-not-found');
    }

    const getLocation: latLong = {
      latitude: geoLocation[0].lat.toString(),
      longitude: geoLocation[0].lon.toString(), // 修复原代码中longitude赋值错误
    };
    // 获取天气数据
    const currentWeatherRes = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?lat=${getLocation.latitude}&lon=${getLocation.longitude}&appid=${apiKey}&units=metric` // 修复units参数格式错误
    );
    const currentWeather = await currentWeatherRes.json();
    const temperature = currentWeather.main.temp;

    // 重定向携带参数
    redirect(`/?city=${encodeURIComponent(data)}&temp=${temperature}`);
  } catch (err) {
    redirect('/?error=fetch-failed');
  }
}
  1. 修改Home Server Component:读取URL搜索参数并展示数据
import Search from "./components/Search";

export default async function Home({ searchParams }: { searchParams: { city?: string; temp?: string; error?: string } }) {
  const { city, temp, error } = searchParams;

  return (
    <>
      <h1>
        {temp ? `当前${city}的温度:${temp}°C` : "请输入城市查询温度"}
      </h1>
      {/* 错误提示 */}
      {error && (
        <p style={{ color: 'red' }}>
          {error === 'empty-input' && '请输入城市名称'}
          {error === 'city-not-found' && '未找到指定城市'}
          {error === 'fetch-failed' && '获取数据失败,请稍后重试'}
        </p>
      )}
      <Search />
    </>
  );
}
  1. 修改Search组件:使用表单提交触发Server Action(规范写法)
'use client';
import { useState } from 'react';
import { create } from '../page';

const Search = () => {
  const [inputVal, setInputVal] = useState("");

  return (
    <form action={create}>
      <input 
        type="text" 
        name="city" 
        value={inputVal}
        onChange={(e) => setInputVal(e.target.value)} 
        placeholder="输入城市名称"
      />
      <button type="submit">查询温度</button>
    </form>
  );
}

export default Search;

方案2:useFormState无刷新展示(客户端交互友好)

通过useFormState钩子接收Server Action返回的结果,在客户端组件中直接展示,无需页面刷新:

  1. 修改create Server Action:返回温度数据或错误信息
interface latLong {
  latitude: string;
  longitude: string;
}

export async function create(formData: FormData) {
  const data = formData.get('city') as string;
  try {
    if (data.trim() === "") {
      return { success: false, error: '请输入城市名称' };
    }

    const apiKey = "123456";
    const geoLocationRes = await fetch(
      `http://api.openweathermap.org/geo/1.0/direct?q=${encodeURIComponent(data)}&appid=${apiKey}`
    );
    const geoLocation = await geoLocationRes.json();

    if (!geoLocation[0]) {
      return { success: false, error: '未找到指定城市' };
    }

    const getLocation: latLong = {
      latitude: geoLocation[0].lat.toString(),
      longitude: geoLocation[0].lon.toString(),
    };
    const currentWeatherRes = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?lat=${getLocation.latitude}&lon=${getLocation.longitude}&appid=${apiKey}&units=metric`
    );
    const currentWeather = await currentWeatherRes.json();
    const temperature = currentWeather.main.temp;

    return { success: true, temperature, city: data };
  } catch (err) {
    return { success: false, error: '获取数据失败,请稍后重试' };
  }
}
  1. 修改Search组件:使用useFormState接收结果并展示
'use client';
import { useState, useFormState } from 'react';
import { create } from '../page';

// 初始化状态
const initialState = { success: false, temperature: 0, city: '', error: '' };

const Search = () => {
  const [inputVal, setInputVal] = useState("");
  const [state, formAction] = useFormState(create, initialState);

  return (
    <>
      <form action={formAction}>
        <input 
          type="text" 
          name="city" 
          value={inputVal}
          onChange={(e) => setInputVal(e.target.value)} 
          placeholder="输入城市名称"
        />
        <button type="submit">查询温度</button>
      </form>
      {/* 展示温度结果 */}
      {state.success && (
        <h2 style={{ marginTop: '1rem' }}>
          当前{state.city}的温度:{state.temperature}°C
        </h2>
      )}
      {/* 错误提示 */}
      {state.error && (
        <p style={{ color: 'red', marginTop: '1rem' }}>
          {state.error}
        </p>
      )}
    </>
  );
}

export default Search;
  1. Home组件无需修改:温度结果直接在Search组件内展示,若需在Home中统一展示,可将Home改为客户端组件或新增客户端组件负责展示。

内容的提问来源于stack exchange,提问作者Abdullahi Abbas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:20:54