如何使用React Hooks Strapi V4.0和Prism建立一个博客

567 阅读8分钟

使用React Hooks Strapi V4.0和Prism构建一个博客

Strapi节省了大量的开发时间,同时让开发者可以自由使用他们喜欢的工具和框架。Strapi,是一个无头的内容管理系统,它是一个只有后端的管理器,允许通过API访问内容,在任何设备上显示。

此外,将Strapi与Angular、React、Nuxt或Vue等多个框架集成,可以简化博客等项目的构建。

通过我们的博客实例,我们将向你展示如何使用状态钩、Strapi和Prism建立一个博客。我们从Strapi传递每一个内容,而博客将启用markdown。这是一个美丽的旅程,我们希望你能跟随我们走完每一步。

前提条件

要继续学习本教程,读者应满足以下要求。

  • 有关于React.js的中级到专业的知识。
  • 必须熟练掌握CSS。
  • 使用Node.js构建过项目。
  • 了解状态钩子。

目标

我们不是要建立一个完整的博客,而是要建立一个包含几篇文章的预览区和一个包含我们支持标记内容的页面的壳。

我们想告诉你如何。

  • 在Strapi中存储内容。
  • 使用状态钩子从Strapi获取数据。
  • 使用Strapi和Prism上的内容创建一个支持markdown的博客。

起步

初始化strapi

在你的编辑器上(在我们的例子中是VsCode),在我们的计算机中创建一个根文件夹,称为base-project ,并在你的终端中使用命令cd base-project

接下来,我们在终端中键入以下命令。

npx create-strapi-app my-project

上述命令将利用node package manager 来创建我们的Strapi项目。它将创建一个名为my-project 的文件夹并安装必要的Strapi节点模块。

为了启动开发服务器,我们在终端运行以下命令。

npm run develop

运行上述命令会在我们的浏览器中打开一个注册区域。这个注册区是用来注册第一个管理员用户的。不幸的是,由于我们已经注册了第一个管理员,所以我们不能给你看。

通过完成这个表格,你就成为Strapi应用程序的第一个管理员用户。

strapi-admin

添加内容

在这一节中,我们要向Strapi添加我们想要的内容。为了开始,我们按照下面的步骤进行。

  • 在插件部分点击content-type builder
  • 接下来,在集合类型下拉菜单中选择create new collection type
  • 一个如下的模式应该弹出。使用你选择的任何显示名称,Strapi会将其复数化。

collection-type

  • 在我们新创建的集合类型中,我们添加了五个新字段(标题、评级、正文、英雄、URL)。

fields

  • 之后,点击侧边栏上的content manager ,选择你的收藏类型。接下来,点击右上角的create new entry ,会被带到一个看起来像这样的页面。

new-entry

每个新条目都包含先前创建的字段的条目。接下来,我们添加所需的文章标题、评级、文章内容(正文)、英雄和URL(英雄图片链接),然后点击保存和发布。

  • 要从Strapi阅读内容,我们前往设置部分,在users and permissions plugin 部分,我们选择角色。

roles

  • 接下来,点击public ,滚动到权限。接下来,点击审查,在权限区选择findfindone 。接下来,向下滚动到上传,做同样的事情,选择上传。

review

现在我们可以在前端进行操作了。

前端

初始化反应

我们首先使用下面的命令在我们的初始根文件夹中创建一个React项目。

npx create-react-app frontend

上面的代码片段将创建一个名为frontend的文件夹,它包含node_module文件夹中的React包。

要启动开发服务器,使用命令npm start 。上述命令在本地服务器上运行React项目,并在浏览器上显示它。

创建前端

为了开始工作,在前端文件夹中,在src 文件夹中创建三个文件夹。命名为componentshookspages 。我们将从pages文件夹开始;创建两个新的JavaScript文件,称为Homepage.jsContents.js

快速提示:在Vscode上,安装ES7插件。它允许你通过快速输入rfc + Enter ,来创建一个React功能组件。

因此,在两个主页和内容文件中键入你的React功能组件。

接下来,回到App.js 文件,做以下工作。

  • 清除默认的React模板。
  • 输入rfc + Enter (如果你已经安装了ES7插件)来添加React功能组件。
  • 导入pages文件夹中的JavaScript文件。
  • 在终端上使用以下命令安装并导入react-router-dom (通常在我们安装React时默认安装)。
npm install react-router-dom
  • 创建一个div ,类名为App ,并使用react-router-dom ,创建通往导入页面的路由。

下面是对上述解释的实现。

import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'

//Page and layout imports
import Homepage from './pages/Homepage'
import Contents from './pages/Contents'

function App() {
  return (
    <Router>
      <div className="App">
        <Siteheader />
        <Routes>
          <Route exact path="/" element={<Homepage />}>
          </Route>
          <Route path="/contents/:id" element={<Contents />}>
          </Route>
        </Routes>
      </div>
    </Router>
  );
}

export default App;

接下来,我们去看Homepage.js 文件。在我们开始之前,我们需要创建我们的状态钩子。因此,在hooks文件夹内,我们将创建一个名为Usefetch.js 的文件。

Usefetch.js 文件内,我们做以下工作。

  • 从React导入useEffectuseState
  • 创建useFetch function ,接收值url ,并导出useFetch() 函数。
import { useEffect, useState } from "react"

const useFetch = (url) => {

}

export default useFetch

注意:钩子接收端点(我们从哪里获得数据)。

  • 在该函数中,添加以下代码。
const [data, setData] = useState([])
const [error, setError] = useState(null)
const [loading, setLoading] = useState(true)
  • 第一个变量是最终从获取请求中获得的数据,通常被设置为空。同时,setData ,更新从Strapi收到的数据。
  • 第二个变量是我们从获取请求中得到的错误,通常被设置为空。setError ,更新从Strapi收到的错误。
  • 第三个变量在我们利用钩子使用fetch时将加载状态初始化为true 。一旦我们完成了对数据的获取,它就会使之成为假的。
  • 接下来,我们将创建一个useEffect 钩子函数,当组件渲染我们使用这个钩子的任何组件时,它就会工作。

useEffect ,我们创建另一个函数叫fetchData ,并使之成为async.

  • 我们使setLoading=true ,以防在我们试图设置数据时,上面的数据变成假的。
  • 我们使用try and catch 语句。然后,我们fetch API ,从端点获取数据。下面是对上述解释的实现。
useEffect(() => {
    const fetchData = async () => {
        setLoading(true)

        try {
            const res = await fetch(url)
            const json = await res.json()
            console.log(json)

            setData(json);
            setLoading(false)
        } catch (error) {
            setError(error)
            setLoading(false)
        }
    }

    fetchData();
}, [url])
  • 我们需要在钩子的结尾处返回数值。我们可以使用这段代码。
return { loading, error, data }

我们的useFetch 已经准备好在我们的Homepage.js 文件和Content.js 文件中使用。

回到Homepage.js 文件。博客的这一部分负责文章的标题和预览(一些文章内容、标题和英雄)。

为了实现这一点,我们按照下面的步骤进行。

  • react-router-dom 中导入Link ,从我们的useFetch.js 文件中导入useFetch
  import useFetch from '../hooks/useFetch'
  import { Link } from 'react-router-dom'
  • Homepage 函数中,通过添加以下代码插入useFetch 组件。
const{loading, error, data} = useFetch('http://localhost:1337/api/reviews')

上面的代码从useFetch 中解构了加载、错误和数据,而url 是Strapi的终端。

  • 创建两个if statements ,以返回一个加载信息和一个错误信息(如果有)。
  if (loading) return <p>Loading...</p>
  if (error) return <p>Error :(</p>

注意:如果加载是true ,或者错误是true ,这是有可能的。在这种情况下,加载是true ,在我们完成获取之前,它仍然是true.

  • 接下来,一旦完成上述工作,我们将需要返回包含我们一些文章内容的模板。我们将使用下面的代码来实现这一点。
  return (
  <div>
    {data.data.map(review => (
      <div key={review.attributes.id} className="review-card">
        <div className="rating">{review.attributes.rating}</div>
        <Link to={`/contents/${review.id}`}>
        <img src={review.attributes.url}/>
        <h2>{review.attributes.title}</h2>
        </Link>
        
        <small>console list</small>

        <p>{review.attributes.body.substring(0, 200)}...</p>
        
      </div>
    ))}
  </div>
)

我们使用data.data.map 函数对从Strapi收到的数据进行映射,我们通过使用一个名为的函数得到对数组中每一项的访问。review.

  • 然后我们返回一个div 模板,其中的key 属性有一个动态值review.attributes.id 。之所以如此,是因为React需要地图内的父元素有一个key 属性,以跟踪Strapi中所有的elements
  • 我们给div 一个类名review-card ,以便以后对其进行样式设计。

注意:关于CSS,我们将不作解释,因为我们相信读者在进入这个阶段之前已经有了很好的背景知识。

  • 使用先前从react-router-dom 中导入的{Link} ,我们创建一个指向内容页的链接标签。然后我们在链接中加入图片和标题。

下面是主页目前的样子。

homepage

对于Content.js 文件,我们首先。

  • useFetch.js 中导入useFetch ,从react-router-dom 中导入useParams
  import { useParams } from 'react-router-dom'
  import useFetch from '../hooks/useFetch'

useParams 是一个用于抓取单一记录的钩子,在这种情况下,我们要从Strapi抓取记录。

  • 接下来,在export default function, 中,我们创建一个常量,并将我们想要的参数名称(id)去结构化,这相当于useParams
const { id } = useParams()

注意:我们称它为id,因为它在我们App.js文件的路由中被命名为id。

  • 通过添加下面的代码插入useFetch 组件。
const{loading, error, data} = useFetch('http://localhost:1337/api/reviews' + id)

上面的代码从useFetch 中解构了加载、错误和数据,而url 是Strapi的端点,id 是我们的解构参数。

  • 创建两个if statements ,如果有的话,返回加载信息和错误信息。
  if (loading) return <p>Loading...</p>
  if (error) return <p>Error :(</p>
  • 接下来,一旦上述工作完成,我们将需要返回包含所选文章内容的模板。我们使用下面的代码来完成。
return (
  <div className="review-card">
    <div className="rating">{data.data.attributes.rating}</div>
    <h2>{data.data.attributes.title}</h2>

    <small>console list</small>

  </div>
)

content

我们必须回到之前创建的组件文件夹,使其启用markdown功能。

在该文件夹中,我们创建一个名为Codeblock.js的文件,并添加以下代码。

import React from "react"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import {dracula} from 'react-syntax-highlighter/dist/cjs/styles/prism';

const CodeBlock = {
  code({node, inline, className, children, ...props}) {
    const match = /language-(\w+)/.exec(className || '')
    return !inline && match ? (
    <SyntaxHighlighter 
      style={dracula} 
      language={match[1]} 
      PreTag="div" {...props}>
      {String(children).replace(/\n$/, '')}
    </SyntaxHighlighter>

    ) : (
      <code className={className} {...props}>
        {children}
      </code>
    )
  }
}

export default CodeBlock
  • 使用上面的代码时,有几个先决条件。
  • 我们需要安装react-syntax-highlighter. ,我们使用下面的代码来完成。
npm install react-syntax-highlighter
  • 接下来,我们从react-syntax-highlighter 模块中导入PrismDracula

  • 为了将其用于我们内容的主体,我们将回到Content.js 文件。

  • content.js 文件中,我们将需要从markdownreact-markdown.

  • 要安装 react-markdown,使用下面的代码。

npm install react-markdown
  • 接下来,我们需要从组件文件夹中导入Codeblock.js (包含我们的语法高亮器的文件)。

例子

import Markdown from 'react-markdown'
import CodeBlock from '../components/CodeBlock'
  • 最后,我们将在我们的div 中添加文章的正文,并将其封装在一个markdown标签中,同时将Codeblock.js 中的语法作为markdown标签中的一个组件属性。

例子

<Markdown components={CodeBlock}>{data.data.attributes.body}</Markdown>

这里是用于博客的整个CSS的链接。

正确地执行上面的代码可以得到下面的结果。

content-body

content-body

我们的博客看起来很好,而且可以正常使用了。

总结

在这篇文章中,我们演示了如何使用状态钩子、Strapi和Prism来创造一个杰作。然而,我们相信你可以更进一步,用这个项目扩大你的范围。