React 实现一个简单的待办事项列表| 青训营

37 阅读3分钟

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),isLoadingerror
    • 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;

image.png

  image.png

导航栏:


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.oktrue),它将退出编辑模式。

 

 const handleInputChange = (e: React.ChangeEvent\<HTMLInputElement | HTMLTextAreaElement>) => {

    const { name, value } = e.target;

    if (editedBlog) {

      setEditedBlog(prevBlog => ({

        ...prevBlog,

        \[name]: value,

      }));

    }

  };

这个函数是一个事件处理器,用于响应输入框和文本区域的值变化。它首先从事件对象中提取namevalue。然后,如果存在editedBlog,它将更新editedBlog的状态。

·  ...prevBlog 使用了扩展操作符,这意味着它会创建prevBlog对象的一个浅拷贝。

·  [name]: value 使用了计算属性名语法,这允许我们基于输入元素的name属性来更新editedBlog的对应属性。例如,如果name是"title",那么这会更新editedBlog的"title"属性。

  image.png

image.png   使用json serve,实现前端全过程

image.png

增加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);

    }

  };

先是状态初始化:

这里定义了四个状态及其对应的设置函数:

  • titlesetTitle: 存储并设置博客标题。
  • bodysetBody: 存储并设置博客正文。
  • authorsetAuthor: 存储并设置博客作者。
  • isLoadingsetIsLoading: 存储并设置一个布尔值,表示是否正在向后端发送数据。
const blog = { title, body, author };

这将前面定义的titlebodyauthor状态组合成一个blog对象。

  • fetch函数向指定的URL发送POST请求,以创建一个新的博客。
  • 如果请求成功,isLoading状态被设置为false,然后使用navigate函数导航回主页。
  • 如果发生错误,它会捕获该错误并在控制台上打印。

总体上,这段代码定义了一个组件的内部状态和逻辑,用于创建新的博客。当用户填写表单并提交时,它会向后端发送数据,并在成功后导航回主页。

  image.png