React+TypeScript+TailwindCss for TodoList
Home组件:
import BlogList from './BlogList';
import useFetch from './useFetch';
const Home = () => {
const { data: blogs, isLoading, error } = useFetch('<http://localhost:3000/blogs>');
return (
// 渲染dom
<>
{error && <div>{error}</div>}
{isLoading && (
<div className="text-xl font-serif h-8 text-center text-pink-600">Loading...</div>
)}
{blogs && <BlogList blogs={blogs} title1="All Blogs" />}
\</>
);
};
export default Home;
Home
组件首先尝试从服务器获取博客列表。当数据正在加载时,它会显示一个加载消息;如果在加载过程中出现错误,它会显示错误信息;当数据加载完毕,它会显示所有的博客。
- 使用useFetch hook从**接口网址**获取数据。>
- useFetch返回一个包含三个属性的对象:data(这里我们将其重命名为blogs),isLoading和error。
-
- blogs:包含从服务器获取的博客列表。
- isLoading:一个布尔值,表示是否正在加载数据。
- error:如果在获取数据时发生错误,此属性将包含错误信息
自定义的useFetch组件为:
import { useEffect, useState } from 'react';
const useFetch = url => {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setTimeout(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
if (!response.ok) {
throw Error('could not fetch ');
}
const data = await response.json();
setData(data);
setIsLoading(false);
setError(null);
} catch (err) {
setIsLoading(false);
// Handle error
setError(err.message);
}
};
fetchData();
}, 1000);
}, []);
return { data, isLoading, error };
};
export default useFetch;
导航栏:
import { NavLink } from 'react-router-dom';
import './index.css';
const Navbar = () => {
return (
<div className="flex justify-between items-center ">
<h1 className="text-6xl ">Todo List</h1>
<div className=" text-lg ">
<button className="mr-8 text-2xl">
<NavLink to="/"> Home</NavLink>
</button>
<button className="text-2xl">
<NavLink to="/create"> New Blog</NavLink>
</button>
</div>
</div>
);
};
export default Navbar;
const handleClick = async () => {
const response = await fetch('网址' + blog.id, {
method: 'DELETE',
});
navigate('/');
};
当
handleClick被调用时,它会发送一个DELETE请求到指定的URL以删除当前的博客文章。完成后,它将导航到主页。
const handleSave = async () => {
if (editedBlog) {
const response = await fetch('网址' + editedBlog.id, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(editedBlog),
});
if (response.ok) {
setIsEditMode(false);
}
}
};
这个函数首先检查是否存在一个
editedBlog。如果存在,它将发送一个PUT请求到服务器以更新博客文章。请求完成后,如果响应是成功的(
response.ok为
true),它将退出编辑模式。
const handleInputChange = (e: React.ChangeEvent\<HTMLInputElement | HTMLTextAreaElement>) => {
const { name, value } = e.target;
if (editedBlog) {
setEditedBlog(prevBlog => ({
...prevBlog,
\[name]: value,
}));
}
};
这个函数是一个事件处理器,用于响应输入框和文本区域的值变化。它首先从事件对象中提取name
和value
。然后,如果存在editedBlog
,它将更新editedBlog
的状态。
· ...prevBlog
使用了扩展操作符,这意味着它会创建prevBlog
对象的一个浅拷贝。
· [name]: value
使用了计算属性名语法,这允许我们基于输入元素的name
属性来更新editedBlog
的对应属性。例如,如果name
是"title",那么这会更新editedBlog
的"title"属性。
使用json serve,实现前端全过程
增加blog组件:
const [title, setTitle] = useState('');
const [body, setBody] = useState('');
const [author, setAuthor] = useState('chen');
const [isLoading, setIsLoading] = useState(false);
const navigate = useNavigate();
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const blog = { title, body, author };
setIsLoading(true);
try {
const response = await fetch('接口地址', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(blog),
});
setIsLoading(false);
navigate('/');
} catch (error) {
console.error(error);
}
};
先是状态初始化:
这里定义了四个状态及其对应的设置函数:
- title和setTitle: 存储并设置博客标题。
- body和setBody: 存储并设置博客正文。
- author和setAuthor: 存储并设置博客作者。
- isLoading和setIsLoading: 存储并设置一个布尔值,表示是否正在向后端发送数据。
const blog = { title, body, author };
这将前面定义的title
、body
和author
状态组合成一个blog
对象。
- 用fetch函数向指定的URL发送POST请求,以创建一个新的博客。
- 如果请求成功,isLoading状态被设置为false,然后使用navigate函数导航回主页。
- 如果发生错误,它会捕获该错误并在控制台上打印。
总体上,这段代码定义了一个组件的内部状态和逻辑,用于创建新的博客。当用户填写表单并提交时,它会向后端发送数据,并在成功后导航回主页。