从刚刚完成的请求中读取数据
Read data from request which just finished
如果用户在输入中输入 id
,我想通过用户输入的特定 ID 获取 post。如果没有,我想获取整个 post 数组,然后从获取的数据中获取一些 id。我知道这没有意义,但它只是为了测试。
它不起作用,因为 useState 异步工作。我尝试了几个解决方案,但所有的解决方案看起来都很丑。
我收到一个错误:
Cannot read properties of undefined (reading 'id')
原因setPosts
还没有设置。
处理这种情况的最好、最明确的方法是什么?
import { useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
const fetchPost = async (id) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
</div>
);
}
就像你说的 useState 工作 asynchronously ,如果你想在改变它之后做一些事情,你将不得不使用 useEffect 并将 posts 设置为它的参数,现在每当 posts 发生突变时,你的函数将是 运行 并且数组的第一个索引将被发送到 fetchPost(id) ,
import axios from "axios";
import "./styles.css";
import { useEffect, useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
useEffect(() => {
if (posts.length) {
fetchPost(posts[0].id);
}
}, [posts]);
const fetchPost = async (id) => {
console.log(`fetching ${id}`);
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
console.log(res.data);
setPost(res.data);
};
const fetchPosts = async () => {
console.log(`fetching all posts`);
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
// res = await fetchPost(posts[0].id); we dont need it here it defined in useffect function
}
};
const setDefaultId = (e) => {
setId(e.target.value);
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setDefaultId(e)} />
<button type="submit">submit</button>
</form>
</div>
);
}
同时考虑永远不要在你的return函数中直接更新状态,这会导致性能问题
问题出在“fetchPost”方法中。在这个方法中,你有两个同名的变量。来自状态挂钩的“id”,以及来自函数参数的“id”。
您可以解决更改这些变量名称之一的问题。
还有一件事,如果“id”没有价值,你获得第一个 post 的方法将不起作用,因为 await 方法不会等待状态的改变。
我修改了一些代码来解决这两个问题。
import { useState } from 'react';
import axios from 'axios';
export default function App() {
const [id, setId] = useState('');
const [post, setPost] = useState(null);
const fetchPost = async (idProp) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${idProp}`,
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
await fetchPost(res.data[0].id);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => {
setId(e.target.value);
}} />
<button type="submit">submit</button>
</form>
</div>
);
}
希望对你有所帮助。
您可以将 fetchPosts 视为 side-effect 并将 fetchPost(posts[0].id)
包装在依赖于 posts
的 useEffect
中。
或者直接在 onSubmit()
中使用结果(假设您不需要 posts
做其他事情)。
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
// setPosts(res.data); // this state is transitory and not used directly by the render
return res.data;
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
const posts = await fetchPosts(); // Only used as part of submit event?
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
<div>{(post && post.title) || "No post yet"}</div>
</div>
);
如果用户在输入中输入 id
,我想通过用户输入的特定 ID 获取 post。如果没有,我想获取整个 post 数组,然后从获取的数据中获取一些 id。我知道这没有意义,但它只是为了测试。
它不起作用,因为 useState 异步工作。我尝试了几个解决方案,但所有的解决方案看起来都很丑。
我收到一个错误:
Cannot read properties of undefined (reading 'id')
原因setPosts
还没有设置。
处理这种情况的最好、最明确的方法是什么?
import { useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
const fetchPost = async (id) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
</div>
);
}
就像你说的 useState 工作 asynchronously ,如果你想在改变它之后做一些事情,你将不得不使用 useEffect 并将 posts 设置为它的参数,现在每当 posts 发生突变时,你的函数将是 运行 并且数组的第一个索引将被发送到 fetchPost(id) ,
import axios from "axios";
import "./styles.css";
import { useEffect, useState } from "react";
export default function App() {
const [id, setId] = useState("");
const [post, setPost] = useState(null);
const [posts, setPosts] = useState([]);
useEffect(() => {
if (posts.length) {
fetchPost(posts[0].id);
}
}, [posts]);
const fetchPost = async (id) => {
console.log(`fetching ${id}`);
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${id}`
);
console.log(res.data);
setPost(res.data);
};
const fetchPosts = async () => {
console.log(`fetching all posts`);
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
setPosts(res.data);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
// res = await fetchPost(posts[0].id); we dont need it here it defined in useffect function
}
};
const setDefaultId = (e) => {
setId(e.target.value);
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setDefaultId(e)} />
<button type="submit">submit</button>
</form>
</div>
);
}
同时考虑永远不要在你的return函数中直接更新状态,这会导致性能问题
问题出在“fetchPost”方法中。在这个方法中,你有两个同名的变量。来自状态挂钩的“id”,以及来自函数参数的“id”。 您可以解决更改这些变量名称之一的问题。
还有一件事,如果“id”没有价值,你获得第一个 post 的方法将不起作用,因为 await 方法不会等待状态的改变。
我修改了一些代码来解决这两个问题。
import { useState } from 'react';
import axios from 'axios';
export default function App() {
const [id, setId] = useState('');
const [post, setPost] = useState(null);
const fetchPost = async (idProp) => {
const res = await axios.get(
`https://jsonplaceholder.typicode.com/posts/${idProp}`,
);
setPost(res.data);
};
const fetchPosts = async () => {
const res = await axios.get('https://jsonplaceholder.typicode.com/posts');
await fetchPost(res.data[0].id);
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
await fetchPosts();
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => {
setId(e.target.value);
}} />
<button type="submit">submit</button>
</form>
</div>
);
}
希望对你有所帮助。
您可以将 fetchPosts 视为 side-effect 并将 fetchPost(posts[0].id)
包装在依赖于 posts
的 useEffect
中。
或者直接在 onSubmit()
中使用结果(假设您不需要 posts
做其他事情)。
const fetchPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`);
// setPosts(res.data); // this state is transitory and not used directly by the render
return res.data;
};
const onSubmit = async (e) => {
e.preventDefault();
if (id) {
await fetchPost(id);
} else {
const posts = await fetchPosts(); // Only used as part of submit event?
await fetchPost(posts[0].id);
}
};
return (
<div className="App">
<form onSubmit={onSubmit}>
<input type="text" onChange={(e) => setId(e.target.value)} />
<button type="submit">submit</button>
</form>
<div>{(post && post.title) || "No post yet"}</div>
</div>
);