如何多次使用不同的JSON数据调用相同的API

huangapple go评论48阅读模式
英文:

How to call same API multiple time with different JSON data

问题

我正在编写一个简单的 React 页面,可以从一个 API 获取用户详细信息,并对其进行一些修改后传递到另一个 API 多次。

export default function User() {
  const [userid, setUserId] = useState("");
  const [userData, setUserData] = useState({});

  const synchToLocation = (loc) => {
    setUserData((userData) => ({ ...userData, id: 1234, location: loc }));
    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(userData)
    };
    fetch("http://localhost:8080/api/v1/synch", requestOptions);
  };

  const handleSynch = () => {
    synchToLocation(1);
    synchToLocation(2);
    synchToLocation(3);
  };

  const fetchUser = (event) => {
    event.preventDefault();
    console.log(userid);
    fetch("http://localhost:8080/api/v1/synch/emp?id=" + userid).then((result) =>
      result.json().then((e) => {
        setUserData({
          ...userData,
          id: e.id,
          firstName: e.firstName,
          lastName: e.lastName,
          role: e.role,
          location: e.location,
          status: e.status
        });
      })
    );
  };

  return (
    <Container>
      <TextField
        id="id"
        label="user id"
        value={userid}
        onChange={(e) => setUserId(e.target.value)}
        fullWidth
        required
      ></TextField>
      <Button
        variant="contained"
        color="secondary"
        type="submit"
        onClick={fetchUser}
      >
        Search
        <SearchOutlined />
      </Button>

      <Box>
        <Button variant="contained" color="secondary" onClick={handleSynch}>
          Synch
        </Button>
      </Box>
    </Container>
  );
}

期望:

  • 如果用户点击“Search”按钮,根据用户输入的 ID 获取用户数据并设置到状态中。
  • 如果用户点击“Synch”按钮,用户数据应更新为特定的位置,并调用更新后的位置的 API。

实际结果:

  • 用户数据在搜索时按预期获取。
  • 有时 API 使用旧数据进行调用,或者有时使用最后更新的数据进行调用

请给我建议如何更好地实现这一点。

英文:

I am writing a simple react page where user details can be fetched from one API and pass it to another API multiple times with some modification.


export default function User() {
const [userid, setUserId] = useState(&quot;&quot;);
const [userData, setUserData] = useState({});
const synchToLocation=(loc)=&gt;{
setUserData((userData)=&gt;({...userData,id:1234,location:loc}));
const requestOptions = {
method: &#39;POST&#39;,
headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
body: JSON.stringify(userData)
};
fetch(&quot;http://localhost:8080/api/v1/synch&quot; , requestOptions);    
}
const handleSynch = () =&gt; {
synchToLocation(1);  
synchToLocation(2);
synchToLocation(3);
};
const fecthUser = (event) =&gt; {
event.preventDefault();
console.log(userid);
fetch(&quot;http://localhost:8080/api/v1/synch/emp?id=&quot; + userid).then((result) =&gt;
result.json().then((e) =&gt; {          setUserData({...userData,id:e.id,firstName:e.firstName,lastName:e.lastName,role:e.role,location:e.location,status:e.status});
})
);
};
return (
&lt;Container&gt;
&lt;TextField
id=&quot;id&quot;
label=&quot;user id&quot;
value={userid}
onChange={(e) =&gt; setUserId(e.target.value)}
fullWidth
required
&gt;&lt;/TextField&gt;
&lt;Button
variant=&quot;contained&quot;
color=&quot;secondary&quot;
type=&quot;submit&quot;
onClick={fecthUser}
&gt;
Search
&lt;SearchOutlined /&gt;
&lt;/Button&gt;
&lt;Box&gt;
&lt;Button variant=&quot;contained&quot; color=&quot;secondary&quot; onClick={handleSynch}&gt;
Synch
&lt;/Button&gt;
&lt;/Box&gt;
&lt;/Container&gt;
);
}

I have one text field and two button (search and synch).
Expectation:

  • if user click search button, fetch userdata for user input id and set to state.
  • if user click Synch button, user data should update with specific location and call api with updated location.

Actual Result:

  • User data fetch on search as expected.
  • Api calling with old data or some time calling with last updated data.

Please suggest me the better way to achieve this.

答案1

得分: 0

问题出在这里。因为setState是异步工作的,所以在setUserData之后,请求主体有时会使用旧的userData而不是您之前设置的新userData。

const synchToLocation = (loc) => {
  setUserData((userData) => ({ ...userData, id: 1234, location: loc }));
  const requestOptions = {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(userData)
  };
  fetch("http://localhost:8080/api/v1/synch", requestOptions);
}

您应该将对象的body属性更改为

body: JSON.stringify({ ...userData, id: 1234, location: loc })
英文:

The problem is here. Because the setState work asynchronously so after setUserData, the request body sometimes use the old userData over the new userData that u have set earlier.

const synchToLocation=(loc)=&gt;{
setUserData((userData)=&gt;({...userData,id:1234,location:loc}));
const requestOptions = {
method: &#39;POST&#39;,
headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },
body: JSON.stringify(userData)
};
fetch(&quot;http://localhost:8080/api/v1/synch&quot; , requestOptions);    
}

you should change the property body of object to

body:JSON.stringify({...userData,id:1234,location:loc})

答案2

得分: -1

Hooks 和 useEffect() 将允许您根据更新后的状态来更新本地状态并重新渲染。

参见:https://reactjs.org/docs/hooks-effect.html

const SimpleComp = (userName, fetchUserAPI, fetchLocalParams) => {

  const [userData, setUserData] = useState(null);
  const [localParams, setLocalParams] = useState(null);

  useEffect(() => {
    setUserData(fetchUserAPI(userName));
  }, []);

  useEffect(() => {
    setLocalParams(fetchLocalParams(userData));
  }, [userData]);

  return (
    <>UserData: {userData}  localParams: {localParams}</>
  );
};

export default SimpleComp;

这两个 Hook 的初始状态均为 null。第一个 useEffect() 使用空的监视参数([])将在加载时被调用。第二个 useEffect() 监视 Hook:userData。当 userData 发生变化时,此 useEffect 将被调用,并使用更新后的状态。第一个 useEffect 在加载时调用 fetchUserData,这会将 userData 更新为 API 调用的返回值。这会使用新值设置 User Data。随后,第二个 useEffect 会被调用,因为 userData-Hook 已更改状态。该 useEffect 调用 fetchLocalParametersAPI,并将该 Hook 的值设置为返回的数据。

在所有 useEffects() 被评估后,Hook 状态的所有更改将触发重新渲染。此时,所有 Hook 变量应该是最新的,并根据 userData 渲染 localParameters。

如果您需要使用同步按钮方法,请创建一个 onClick,该 onClick 从文本输入中设置一个新的 userName Hook,并在 onClick() 中更新 userName。只需创建另一个 useEffect,监视 userName,并使用新的用户名调用 fetchUserDataAPI。这将更新 userData Hook,然后在 userData 发生变化时调用 fetchLocalParams。

英文:

Hooks and useEffect() will allow you to update local state and re-render based on this updated state.

see: https://reactjs.org/docs/hooks-effect.html

const SimpleComp = (userName, fetchUserAPI, fetchLocalParams) =&gt; {
const [userData, setUserData] = useState(null);
const [localParams, setLocalParams] = useState(null);
useEffect(() =&gt; {
setUserData( fetchUserAPI(userName) );
}, []);
useEffect(() =&gt; {
setLocalParams( fetchLocalParams(userData) );
}, [userData]);
return (
&lt;&gt;UserData: {userData}  localParams: {localParams}&lt;/&gt;
);
};
export default SimpleComp;

The initial-state for both Hooks is null. The first useEffect() with empty watch parameters ([]) will be called on-load. The second useEffect() is watching the Hook: userData. When userData changes; this useEffect will be called with the updated state. The first calls the fetchUserData on-load. This updates userData to the return from the API call. This sets User Data with the new value. The second useEffect will then be called because the userData-Hook has changed state. That useEffect calls the fetchLocalParametersAPI and sets this Hook's value to the returned data.

All of these changes in Hook state triggers re-render after all of the useEffects() have been evaluated. At that time; all of the Hook variables should be up-to-date and rendering the localParameters based on the userData.

If you need to use the sync button approach; then create an onClick that sets a new userName Hook from a text-input and update userName onClick(). Just create another useEffect that watches userName and calls fetchUserDataAPI with the new username. This will update the userData Hook which will then call fetchLocalParams when userData changes.

huangapple
  • 本文由 发表于 2023年2月16日 06:18:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465953.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定