快速搭建服务器,fetch请求从服务器获取数据

1.strapi

首先strapi是一个api管理系统,可以让我们直接用网页的形式去定义自己的api,包括设置模型和权限等功能。

首先直接在项目目录里面安装库。npx create-strapi@latest server --quickstart这样就可以直接在项目目录创建一个连接数据库的服务器了。不用我们去书写代码,直接在网页版数据库添加表以及表中的数据就可以自动生成api让我们去访问请求了。

​编辑

就是这种,我们网页形式创建表,添加权限,自动生成api。这样我们就可以在前端发送请求去获取数据了。值得一提的是记得npm的版本以及node.js版本会有限制。

可以装一个nvm管理自己开发项目用的node。

我是mac系统所以用brew安装nvm brem install nvm,然后创建nvm工作目录 mkdir ~/.nvm

然后配置终端环境变量,nano ~/.zshrc 然后文件内容

bash 复制代码
Maestro CLI
export PATH="$HOME/.maestro/bin:$PATH"

OpenJDK 17
export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"

nvm 配置(Homebrew 路径,Apple M 芯片)
export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && . "/opt/homebrew/opt/nvm/nvm.sh"
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && . "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"

然后control x退出 按y 再按回车保存退出成功。在执行立即生效命令 source ~/.zshrc这样nvm就配置好了。我们用nvm install 22装上 22版本的node.js然后nvm use 22就可以创建strapi项目了。

2.fetch

上面网页可以看到我们路由是/api/students,那么我们就可以尝试去用fetch(浏览器自带的发送请求的api,是浏览器提供的全局函数,返回的一个promise)所以可以用链式调用.then.catch因为promise有状态,请求成功自动执行.then失败会自动调用.catch而且参数就是返回的promise实例对象。

javascript 复制代码
import React, { useEffect } from 'react'

export default function App() {
    const [person, setPerson] = React.useState([])
    const [show, setShow] = React.useState(false)
    /*
        从接口http://localhost:1337/api/students中加载数据
        组件一渲染就向服务器发送请求加载数据
        组件初始化时候发送请求来加载数据
    */
    useEffect(() => {
        //说明数据开始加载了
        setShow(true)
        //发送请求
        //fetch()用来向服务器发送请求加载数据,Ajax的升级版
        //需要两个参数 1.请求地址2.请求信息
        //promise两个特点 成功和失败两个回调函数.then成功时候调用 .catch失败时调用
        fetch('http://localhost:1337/api/students/')
            .then((res) => {
                //response表示响应信息
                // console.log(res);
                return res.json();//该方法可以将响应的json直接转换为js对象
            }).then((data) => {
                console.log(data.data);
                // 将加载到的数据设置进state中
                setPerson(data.data)
                setShow(false)
            })
            .catch(() => { })
    }, [])
    return (
        <div>
            {show ? (
                <p>正在加载中...</p>
            ) : (
                person.map((item) => (
                    <div key={item.id}>
                        {item.name} --- {item.gender} --- {item.age}
                    </div>
                ))
            )}
        </div>
    )
}

这里我们没有写fetch发送请求的类型,所以是get。这里展示数据成功,说明访问成功之后把数据返回来了,但是第一次是json类型

​编辑

我们需要去转化成对象。比如这里再次使用.then是因为前面的.then把json转化为js对象。然后return返回的也是一个promise实例对象。所以可以.then,报错.catch捕捉。

​编辑

这里转化的js对象有两个属性一个是data,一个是meta(不认识),但是我们展开确定我们需要的是data里面的对象​编辑

所以用setState去存住返回来的数据就可以去展示到页面上面了。就实现了第一次用fetch请求api响应数据展示的过程了。

但是我们要知道还有一个.catch我们没有去写,比如我们去掉路由students中的s,

​编辑

​编辑

返回404但是问题是map也就是map方法错了所以请求整个过程还是执行了?这很明显不对。但是我们看到ok变为false,那么我们就可以去截断这个请求过程。而且statusText都变了。

​编辑

对比我们就知道如果错了,ok和statueText会改变,那就对这些进行判断。

​编辑

比如这里,这样如果错误就不会再执行请求后面的代码了。因为只有成功才会返回promise实例对象,才可以调用后面的.then,而且.catch没有内容所以什么都没有。

javascript 复制代码
import React, { useEffect } from 'react'

export default function App() {
    const [person, setPerson] = React.useState([])
    const [show, setShow] = React.useState(false)
    const [err, setError] = React.useState(null)
    /*
        从接口http://localhost:1337/api/students中加载数据
        组件一渲染就向服务器发送请求加载数据
        组件初始化时候发送请求来加载数据
    */
    useEffect(() => {
        //说明数据开始加载了
        setShow(true)
        //发送请求
        //fetch()用来向服务器发送请求加载数据,Ajax的升级版
        //需要两个参数 1.请求地址2.请求信息
        //promise两个特点 成功和失败两个回调函数.then成功时候调用 .satch失败时调用
        fetch('http://localhost:1337/api/students/')
            .then((res) => {
                //判断是否正常返回响应信息
                if (res.ok) {
                    console.log(res);
                    return res.json()
                }
                //代码运行到这里 说明没有加载到数据
                // setShow(false)
                //抛出一个错误
                throw new Error('数据加载失败')
                // response表示响应信息
                // console.log(res);
                // return res.json();//该方法可以将响应的json直接转换为js对象
            }).then((data) => {
                // console.log(data);
                // 将加载到的数据设置进state中
                setPerson(data.data)
                setShow(false)
            })
            .catch((e) => {
                //catch中的回调函数用来统一处理错误
                //catch执行说明上面代码出错
                setShow(false)
                // console.log(e);
                console.log('e', e)
                setError(e)
            })
    }, [])
    return (
        <div>
            {show && <p>加载中</p>}
            {err && <p>出错了:{err.message}</p>}
            {!show && !err && person.map((item) => (
                <div key={item.id}>
                    {item.name} --- {item.gender} --- {item.age}
                </div>
            ))}
        </div>
    )
}

当报错的时候用throw new Error('')扔出一个err,然后.catch就可以捕捉到。这样就完成了整个请求的逻辑,首先要有一个state接收响应数据,还要有一个state去控制请求发送后如果没有即使响应展示的内容,还需要一个state去控制页面如果报错了展示错误信息,

3.async await语法糖

javascript 复制代码
import React, { useEffect } from 'react'

export default function App() {
    const [person, setPerson] = React.useState([])
    const [show, setShow] = React.useState(false)
    const [err, setError] = React.useState(null)
    useEffect(() => {

        const fetData = async () => {
            try {
                setShow(true)
                setError(null)
                const res = await fetch('http://localhost:1337/api/students')
                if (res.ok) {
                    const data = await res.json()
                    setPerson(data.data)

                } else {
                    throw new Error('数据加载失败!')
                }
            } catch (e) {
                setError(e)
            } finally {
                setShow(false)
            }
        }




        fetData()
    }, [])
    return (
        <div>
            {show && <p>加载中</p>}
            {err && <p>出错了:{err.message}</p>}
            {!show && !err && person.map((item) => (
                <div key={item.id}>
                    {item.name} --- {item.gender} --- {item.age}
                </div>
            ))}
        </div>
    )
}

最开始我们使用 fetch 是通过连续调用 .then 来一步步获取 response 和 json 数据,因为 fetch 返回的是一个 Promise 实例对象,不能直接取到里面的数据。而使用 await 关键字后,就相当于自动帮我们调用了 .then,把 Promise 解析后的数据直接赋值给变量。比如第一次用 await fetch... 获取响应对象 response,第二次再用 await response.json() 把 JSON 数据解析成 JS 对象。

由于 await 是同步语法风格,我们就不能再用 .catch 来捕获错误,而需要使用 try catch finally 来捕获异常,比如 throw 抛出的错误才能在 catch 中处理。需要注意的是:只有在 async 声明的函数中才能使用 await。

4.删除数据

javascript 复制代码
import React, { } from 'react';
import StuContext from './store/StuContext';
import StudentForm from './StudentForm';
const Student = (props) => {
    const Stx = React.useContext(StuContext)
    const [loading, setLoading] = React.useState(false)
    const [error, setError] = React.useState(null)
    const [isEdit, setIsEdit] = React.useState(null)
    const deleteData = React.useCallback(async () => {
        try {
            setLoading(true)
            setError(null)

            const res = await fetch(http://localhost:1337/api/students/${props.stu.documentId}, {
                method: 'delete'
            })
            if (!res.ok) {
                throw new Error('删除失败')
            }
            //修改成功后触发列表重新刷新
            Stx.fetchData()
            // const data = await res.json()
            // console.log('data', data)
            // 被删除的学生
        } catch (e) {
            console.log(e);
            setError(e)
        } finally {
            setLoading(false)
        }
    }, [])

    const Delete = () => {
        //删除学生
        deleteData()
    }

    const cancel = () => {
        setIsEdit(false)
    }

    return (
        <>
            {!isEdit &&
                <tr>
                    <td>{props.stu.name}</td>
                    <td>{props.stu.gender}</td>
                    <td>{props.stu.age}</td>
                    <td>{props.stu.address}</td>
                    <td>
                        <button onClick={Delete} >删除</button>
                    </td>
                    <td>
                        <button onClick={() => { setIsEdit(true) }} >修改</button>
                    </td>
                </tr>
            }
            {
                isEdit && <StudentForm stu={props.stu} onCancel={cancel} />
            }
            {
                loading && <tr><td colSpan={5}>正在删除数据</td></tr>
            }
            {
                error && <tr><td colSpan={5}>删除失败</td></tr>
            }
        </>

    );
};

export default Student;

这是我们的删除请求,我们只需要在后面的对象中指名请求头为delete就可以去删除了。当然需要一个参数documentId去指名删除的哪一个。id不行在说一边我用的strapi不支持id去指定删除或者更新的表中的列。卡了一天了.............只不过一个点是Context我们用到了,因为我们

​编辑

​编辑

每次在删除之后需要重新加载一遍数据,保证最新的数据在 页面上。

xml 复制代码
     <StuContext.Provider value={{ fetchData }}>
            <div className="app">
                <button onClick={() => { loadDataHandler() }}>加载数据</button>
                {(!loading && !error) && <StudentList stus={stuData} />}
                {loading && <p>数据正在加载中...</p>}
                {error && <p>数据加载异常!</p>}
            </div>
        </StuContext.Provider>

就是这样然后我们在删除请求成功之后,执行一下重新加载的方法就好了。

5.创建以及更新请求

javascript 复制代码
import React from 'react'
import './StudentForm.css'
import StuContext from './store/StuContext'
export default function StudentForm(props) {
    const Stx = React.useContext(StuContext)
    const [input, setInput] = React.useState({
        name: props.stu ? props.stu.name : '', age: props.stu ? props.stu.age : '',
        address: props.stu ? props.stu.address : '', gender: props.stu ? props.stu.gender : '男'
    })
    const [loading, setLoading] = React.useState(false)
    const [err, setErr] = React.useState(null)
    const addData = (async (input) => {
        try {
            setLoading(true)
            setErr(null)
            const res = await fetch('http://localhost:1337/api/students', {
                method: 'post',
                body: JSON.stringify({
                    data: input
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            console.log('res.ok', res.ok)
            if (!res.ok) {
                throw new Error('添加失败')
            }
            //添加成功刷新列表
            Stx.fetchData()

        } catch (e) {
            console.log(e);

            setErr(e)
        } finally {
            setLoading(false)
        }
    })
    const updataData = (async (newStu, id) => {
        try {
            setErr(null)
            setLoading(true)
            const res = await fetch(http://localhost:1337/api/students/${id}, {
                method: 'PUT',
                body: JSON.stringify({ data: newStu }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            if (!res.ok) {
                throw new Error('修改出错')
            }
            Stx.fetchData()
        } catch (e) {
            setErr(e)
        } finally {
            setLoading(false)
        }
    })
    const nameChange = (e) => {
        setInput((preState) => ({ ...preState, name: e.target.value }))
    }
    const ageChange = (e) => {
        setInput((preState) => ({ ...preState, age: +e.target.value }))
    }
    const genderChange = (e) => {
        setInput((preState) => ({ ...preState, gender: e.target.value }))
    }
    const addressChange = (e) => {
        setInput((preState) => ({ ...preState, address: e.target.value }))
    }
    const handle = () => {
        addData(input)
    }
    const updataHandle = () => {
        updataData(input, props.stu.documentId)
    }
    return (

        <>

            <tr className='student-form'>
                <td><input type="text" onChange={nameChange} value={input.name} /></td>
                <td><select name="" id="" onChange={genderChange} value={input.gender}>
                    <option value="男">男</option>
                    <option value="女">女</option>
                </select></td>
                <td><input type="text" onChange={ageChange} value={input.age} /></td>
                <td><input type="text" onChange={addressChange} value={input.address} /></td>

                <td>
                    {props.stu && <><button onClick={() => { props.onCancel() }}>取消</button><button onClick={updataHandle}>修改</button></>}
                    {!props.stu && <button onClick={handle}>添加</button>}

                </td>
            </tr>
            {loading && <tr><td colSpan={5}>添加中</td></tr>}
            {err && <tr><td colSpan={5}>添加失败</td></tr>}
        </>
    )
}

唯一不同的是我们在执行创建或者更新请求除了请求头不同以外,创建也就是添加新表元素需要传一个json格式的文本内容,也就是我们需要把js对象转化成json格式。正好对应我们响应体json格式需要转化成js对象我们用。以及指明请求体的格式,headers:{"Content-Type:'application/json'"}说明我们传过去的是json格式。包括更新,毕竟我们是传过去数据而不是get获取数据。这一点要注意。好了现在我们用fetch实现了post 增 delete删 put 改 get查了。虽然不熟练但至少有个思路怎么去数据库拿东西了。至于优化还是慢慢来吧。

相关推荐
中微子23 分钟前
React 状态管理 源码深度解析
前端·react.js
加减法原则1 小时前
Vue3 组合式函数:让你的代码复用如丝般顺滑
前端·vue.js
yanlele2 小时前
我用爬虫抓取了 25 年 6 月掘金热门面试文章
前端·javascript·面试
lichenyang4532 小时前
React移动端开发项目优化
前端·react.js·前端框架
你的人类朋友2 小时前
🍃Kubernetes(k8s)核心概念一览
前端·后端·自动化运维
web_Hsir2 小时前
vue3.2 前端动态分页算法
前端·算法
烛阴3 小时前
WebSocket实时通信入门到实践
前端·javascript
草巾冒小子3 小时前
vue3实战:.ts文件中的interface定义与抛出、其他文件的调用方式
前端·javascript·vue.js
DoraBigHead3 小时前
你写前端按钮,他们扛服务器压力:搞懂后端那些“黑话”!
前端·javascript·架构
Xiaouuuuua4 小时前
一个简单的脚本,让pdf开启夜间模式
java·前端·pdf