Как да създадете приложение за задачи с помощта на Next.js и Strapi

Актуализирано през юли 2023 г.

В тази статия ще научим как да използваме Strapi, Next.js и GraphQL, за да създадем просто приложение за задачи.

Какво е Strapi?

Strapi е най-модерната Node.js Headless Content Management System с отворен код, използвана за изграждане на мащабируеми, сигурни, готови за производство API бързо и ефективно, спестявайки на разработчиците безброй часове развитие. Със своята разширяема система за плъгини, той предоставя огромен набор от вградени функции: административен панел, управление на удостоверяване и разрешения, управление на съдържанието, генератор на API и др. Strapi е 100% отворен код, което означава :

  • Strapi е напълно безплатен.
  • Можете да го хоствате на вашите сървъри, така че да притежавате данните.
  • Той е напълно персонализиран и разширяем, благодарение на системата за добавки.

Какво е Next.js?

Next.js е олекотена рамка React за създаване на изобразени от сървър приложения. Next.js ще се погрижи за тежкото вдигане на компилацията на приложението, като разделяне на код, HMR (гореща подмяна на модули) SSR (изобразяване от страна на сървъра) и ще ни позволи да се съсредоточим върху писането на кода, а не нашата конфигурация за изграждане.

Какво е GraphQL?

GraphQL е език за заявки, който позволява на предния край на приложение лесно да прави заявки към API на приложението. Всяка заявка изисква само данните, необходими за изобразяване от текущия изглед. Това позволява на програмиста да създаде страхотно потребителско изживяване на множество устройства и размери на екрана.

Strapi гарантира, че следваме най-добрите практики, когато създаваме и използваме уеб ресурси през HTTP.

Например имаме книжен ресурс: /books. HTTP глаголите обозначават действието, което трябва да се извърши върху ресурсите на книгата. Книгите стават колекция и може да се добави нова книга, книга може да се редактира и книга може също да се изтрие.

Следната CRUD заявка може да бъде изпълнена на книжния ресурс с помощта на:

  • ПУБЛИКАЦИЯ api/books
  • ВЗЕМЕТЕ api/books и api/books/:id, за да получите конкретна книга
  • ПОСТАВЕТЕ api/books/:id
  • ИЗТРИВАНЕ api/books/:id

Книгите се превръщат в колекция и може да се изпълни всяко от CRUD действията по-горе.

Предпоставки

За да следвате ефективно тази статия, уверете се, че имате:

  • Node.js: Поддържат се само версии за поддръжка и LTS (v14, v16 и v18).
  • Node v18.x се препоръчва за Strapi v4.3.9 и по-нови
  • Възел v16.x се препоръчва за Strapi v4.0.x до v4.3.8.
  • Мениджър на пакети, за предпочитане Yarn.
  • Можете да инсталирате yarn с помощта на npm i -g yarn, който ще инсталира yarn глобално
  • Основни познания за NextJS
  • Редактор на код, за предпочитане Visual Studio Code.

Сега, когато всичко е готово, можем да започнем да създаваме приложението за задачи.

Настройване на Strapi

Преди да можем да настроим Strapi, трябва да създадем папка, която ще съдържа изходния код. Отворете вашия терминал в желаната от вас директория и изпълнете кода по-долу:

mkdir strapi-todo-blog
  cd strapi-todo-blog

След това отворете папката strapi-todo-blog в Visual Studio Code. Сега можем да стартираме следните редове код в интегрирания терминал на Vs Code, за да инсталираме Strapi.

npx create-strapi-app@latest todo-api --quickstart

След като инсталацията е успешна, ще получите успешно съобщение, подобно на това по-долу:

След това ще бъдете пренасочени към уеб страницата на администратора. Това е мястото, където ще създадете своя първи администратор. Попълнете исканата информация и щракнете върху бутона Да започнем.

ако не сте пренасочени и приложението Strapi не работи във вашия терминал, тогава стартирайте Strapi с помощта на yarn develop и отидете ръчно до http://localhost:1337/admin/auth/register-admin

Щракването върху бутона ще създаде вашето администраторско табло, както се вижда по-долу:

Създаване на колекции

Сега ще създадем уеб ресурсите. Отидете на Content-Types Builder и щракнете върху тип Create new collection. Ще се появи модал, въведете todo като показвано име и щракнете върху продължи.

Ще се появи модал, където избираме полето за нашия тип колекция. Кликнете върху Text.

Въведете todoText и щракнете върху бутона Край ****

След като създадете полето todoText, щракнете върху запазване горе вдясно. Това ще накара сървъра на Strapi да се рестартира. След като Strapi се рестартира успешно, щракнете върху Мениджър на съдържанието в страничната навигационна лента, изберете типа колекция задачи и Създайте нов запис .

След това въведете задача в todoText, щракнете върху запазване и след това върху публикуване.

Задачата ще бъде подобна на тази по-долу, съдържаща TODOTEXT, CREATEDAT, UPDATEDAT и STATE:

Разрешаване на достъп

Strapi е проектиран да осигури сигурност за вашето приложение чрез ограничаване на достъпа до различните крайни точки на API. Извършването на CRUD заявка към todo тип колекция без предоставяне на разрешение ще доведе до 403 Забранена грешка, както се вижда по-долу.

В Strapi има две роли, за които може да се даде разрешение.

  • Удостоверени потребители: За потребители, които са влезли в системата.
  • Публични (неупълномощени потребители): За потребители, които не са влезли
  • Поради простотата на това приложение, ние няма да разработваме система за влизане. Чувствайте се свободни да разгледате тази статия, за да създадете такава.

За да предоставите достъп:

  • Придвижете се до Настройки и след това до Роли и разрешения.
  • Кликнете върху ролята Public.
  • Отворете акордеона, намерен в секцията Todo.
  • Поставете отметка в квадратчето Select all.
  • Кликнете върху Запазване горе вдясно.

Сега, когато се опитаме да направим предишната заявка отново, получаваме 200 успешно съобщение, както е показано:

Активиране на GraphQL

По подразбиране API, генерирани със Strapi, са REST крайни точки. Крайните точки могат лесно да бъдат интегрирани в GraphQL крайни точки с помощта на интегрирания GraphQL плъгин. За да инсталирате GraphQL в приложението, отворете папката todo-api във вашия терминал и изпълнете реда с код по-долу:

npm install @strapi/plugin-graphql

След като бъде инсталиран успешно, рестартирайте вашия Strapi сървър, отидете до http://localhost:1337/graphql и опитайте тази заявка:

query Todo {
  todos {
    data {
      id
      attributes {
        todoText
      }
    }
  }
}

Трябва да получите изход, подобен на този по-долу.

Изграждане на приложението Next.js

Изградихме API на Strapi и следващата стъпка е да създадем интерфейса.

Уверете се, че сте в директорията strapi-todo-blog

Отворете вашия терминал в директорията strapi-todo-blog и изпълнете кода по-долу, за да инсталирате NextJS.

npx create-next-app@latest todo-app

Изпълнението на командата create-next-app ще ви зададе няколко въпроса, следвайте подканите и отговорете според вашите предпочитания или както е показано по-долу:

Настройване на Apollo

В този урок ще използваме Apollo Client, за да свържем нашето приложение NextJS с крайната точка на graphql на Strapi. Отворете своя терминал в папката todo-app и изпълнете кода по-долу, който инсталира всички зависимости, необходими за работата на Apollo:

npm install @apollo/client@alpha @apollo/experimental-nextjs-app-support --legacy-peer-deps

Сега създайте папка в директорията src, наречена lib и създайте файл в нея с име client.tsx След като файлът бъде създаден, ще приложим логиката на Apollo в новосъздадения файл.

// src/lib/client.tsx
"use client";
import { HttpLink, SuspenseCache, ApolloLink } from "@apollo/client";
import {
  NextSSRApolloClient,
  ApolloNextAppProvider,
  NextSSRInMemoryCache,
  SSRMultipartLink,
} from "@apollo/experimental-nextjs-app-support/ssr";
const STRAPI_URL = process.env.STRAPI_URL || "http://localhost:1337";
function makeClient() {
  const httpLink = new HttpLink({
    uri: `${STRAPI_URL}/graphql`,
  });
  return new NextSSRApolloClient({
    cache: new NextSSRInMemoryCache(),
    link:
      typeof window === "undefined"
        ? ApolloLink.from([
            new SSRMultipartLink({
              stripDefer: true,
            }),
            httpLink,
          ])
        : httpLink,
  });
}
function makeSuspenseCache() {
  return new SuspenseCache();
}
export function ApolloWrapper({ children }: React.PropsWithChildren) {
  return (
    <ApolloNextAppProvider
      makeClient={makeClient}
      makeSuspenseCache={makeSuspenseCache}
    >
      {children}
    </ApolloNextAppProvider>
  );
}

По-горе създадохме Apollo-wrapper доставчик. Този доставчик ще обвие React.ReactNode (children), позволявайки на Apollo да работи върху всички компоненти от страна на клиента на приложението. След това ще импортираме доставчика Apollo-wrapper в layout.tsx.

// src/app/layout.tsx
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { ApolloWrapper } from "@/lib/client"; //Importing the ApolloWrapper Provider
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
  title: "Todo app",
  description: "Generated by Fredrick Emmanuel",
};
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className} suppressHydrationWarning={true}>
        <ApolloWrapper>
          {/* Wrapping the React.ReactNode*/}
          {children}
        </ApolloWrapper>
      </body>
    </html>
  );
}

Чувствайте се свободни да разгледате тази статия за справка

Настройка на Frontend

Нашето приложение за задачи ще изглежда така:

Ще го разделим на различни компоненти:

Разделите Header и TodoItem ще бъдат в папка, наречена components, докато AddTodo и TodoList ще бъдат в containers. Създайте нова папка с име components в директорията src и създайте два файла: Header.tsx и TodoItem.tsx. След това създайте друга папка в директорията src, наречена containers и създайте два файла: AddTodo.tsx и Todolist.tsx. Вашата src директория трябва да изглежда така:

📂src
┃ ┣ 📂app
┃ ┃ ┣ 📜favicon.ico
┃ ┃ ┣ 📜globals.css
┃ ┃ ┣ 📜layout.tsx
┃ ┃ ┣ 📜page.module.css
┃ ┃ ┗ 📜page.tsx
┃ ┣ 📂components
┃ ┃ ┣ 📜Header.tsx
┃ ┃ ┗ 📜TodoItem.tsx
┃ ┣ 📂containers
┃ ┃ ┣ 📜AddTodo.tsx
┃ ┃ ┗ 📜TodoList.tsx
┃ ┗ 📂lib
┃ ┃ ┗ 📜client.tsx

Нека изясним файловете: Отворете файла globals.css и заменете кода в него с кода по-долу:

/* src/app/globals.css */
html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu,
    Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
  font-size: xx-large;
}
a {
  color: inherit;
  text-decoration: none;
}
* {
  box-sizing: border-box;
}
.main {
  padding: 10px 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}
.header {
  display: flex;
  justify-content: center;
  color: rgba(70, 130, 236, 1);
}
.todoInputText {
  padding: 10px 7px;
  border-radius: 3px;
  margin-right: 2px;
  margin-left: 2px;
  width: 100%;
  font-size: large;
}
button {
  padding: 10px 10px;
  border-radius: 3px;
  cursor: pointer;
  margin-right: 2px;
  margin-left: 2px;
  font-size: large;
}
.bg-default {
  background-color: rgba(70, 130, 236, 1);
  border: 1px solid rgba(28, 28, 49, 1);
  color: white;
}
.bg-danger {
  background-color: red;
  border: 1px solid rgba(28, 28, 49, 1);
  color: white;
}
.todoInputButton {
  padding: 10px 10px;
  border-radius: 3px;
  background-color: rgba(70, 130, 236, 1);
  color: white;
  border: 1px solid rgba(28, 28, 49, 1);
  cursor: pointer;
  margin-right: 2px;
  margin-left: 2px;
  font-size: large;
}
.addTodoContainer {
  margin-top: 4px;
  margin-bottom: 17px;
  width: 500px;
  display: flex;
  justify-content: space-evenly;
}
.todoListContainer {
  margin-top: 9px;
  width: 500px;
}
.todoItem {
  padding: 10px 4px;
  color: rgba(70, 130, 236, 1);
  border-radius: 3px;
  border: 1px solid rgba(28, 28, 49, 1);
  margin-top: 9px;
  margin-bottom: 2px;
  display: flex;
  justify-content: space-between;
}
.todosText {
  padding-bottom: 2px;
  border-bottom: 1px solid;
}

След това отворете файла Header.tsx и добавете следното:

// src/components/Header.tsx
export default function Header() {
  return (
    <div className="header">
      <h2>ToDo app</h2>
    </div>
  );
}

Сега ще импортираме компонента Header и ще го поставим над React.ReactNode във файла layout.tsx

// src/app/layout.tsx
import "./globals.css";
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { ApolloWrapper } from "@/lib/client"; //Importing the ApolloWrapper Provider
const inter = Inter({ subsets: ["latin"] });
import Header from "@/components/Header";

//The rest of the code

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className} suppressHydrationWarning={true}>
        <ApolloWrapper>
          {/* Wrapping the React.ReactNode*/}
          <Header />
          {/* Header */}
          {children}
        </ApolloWrapper>
      </body>
    </html>
  );
}

В AddTodo.tsx добавете:

// src/container/AddTodo.tsx
import { useState } from "react";
function AddTodo({ addTodo }: { addTodo: FunctionStringCallback }) {
  const [todo, setTodo] = useState<string>("");
  return (
    <>
      <div className="addTodoContainer">
        <input
          className="todoInputText"
          type="text"
          placeholder="Add new todo here..."
          id="todoText"
          value={todo}
          onChange={(e) => {
            setTodo(e.target.value);
          }}
          onKeyDown={(e) => {
            if (e.code === "Enter") {
              addTodo(todo);
              setTodo("");
            }
          }}
        />
        <input
          className="todoInputButton"
          type="button"
          value="Add Todo"
          onClick={() => {
            addTodo(todo);
            setTodo("");
          }}
        />
      </div>
    </>
  );
}
export default AddTodo;

Въз основа на кода по-горе, извлякохме функцията addTodo от props и извикахме функцията, когато се натисне Enter или когато се щракне върху бутона Add Todo. Тази функция изпраща стойността на входа (todo), като използва предаване на проп от дете към родител. Отворете файла TodoItem.tsx и добавете следното към него:

// src/coomponents/TodoItem.tsx
interface ItemTodo {
  todo: any;
  editTodoItem: FunctionStringCallback;
  deleteTodoItem: FunctionStringCallback;
}
function TodoItem({ todo, editTodoItem, deleteTodoItem }: ItemTodo) {
  return (
    <>
      <div className="todoItem">
        <div>{todo.attributes.todoText}</div>
        <div>
          <i>
            <button className="bg-default" onClick={() => editTodoItem(todo)}>
              Edit
            </button>
          </i>
          <i>
            <button className="bg-danger" onClick={() => deleteTodoItem(todo)}>
              Del
            </button>
          </i>
        </div>
      </div>
    </>
  );
}
export default TodoItem;

Кодът по-горе показва всяка задача, състояща се от бутоните todoText, Edit и Del. След това импортирайте TodoItem във файла TodoList.tsx.

// src/containers/TodoList.tsx
import TodoItem from "@/components/TodoItem";
interface ListTodo {
  todos: any;
  editTodoItem: any;
  deleteTodoItem: any;
}
function TodoList({ todos, editTodoItem, deleteTodoItem }: ListTodo) {
  return (
    <div className="todoListContainer">
      <div className="todosText">Todos</div>
      {todos
        ?.sort((a: any, b: any) =>
          b.attributes.createdAt.localeCompare(a.attributes.createdAt)
        )
        .map((todo: any) => {
          return (
            <TodoItem
              todo={todo}
              key={todo.id}
              deleteTodoItem={deleteTodoItem}
              editTodoItem={editTodoItem}
            />
          );
        })}
    </div>
  );
}
export default TodoList;

Този код преминава през todos и показва всеки TodoItem. И накрая, ще импортираме файла AddTodo.tsx и TodoList.tsx във файла pages.tsx и ще предадем съответните им подпори.

// src/app/page.tsx
"use client";
import { useEffect, useState } from "react";
import AddTodo from "@/containers/AddTodo";
import TodoList from "@/containers/TodoList";
export default function Home() {
  const [todos, setTodos] = useState<[]>([]);
  const addTodo = async (todoText: string) => {};
  const editTodoItem = async (todo: any) => {
    console.log("Edited");
  };
  const deleteTodoItem = async (todo: any) => {
    console.log("Deleted");
  };
  return (
    <div>
      <main className="main">
        <AddTodo addTodo={addTodo} />
        <TodoList
          todos={todos}
          deleteTodoItem={deleteTodoItem}
          editTodoItem={editTodoItem}
        />
      </main>
    </div>
  );
}

Създаване на CRUD заявки

Стигнахме до основната част на този урок. В този раздел ще се справим

  • Извличане на всички задачи
  • Създаване на задача
  • Редактиране на задача и
  • Изтриване на задача от Headless CMS на Strapi.

Да започнем 🎉.

Извличане на всички задачи

Създайте папка в директорията src, наречена query, създайте файл с име schema.tsand add the following lines of code to theschema.ts` file.

// src/query/schema.ts
import { gql } from "@apollo/client";
export const GETQUERY = gql`
  {
    todos(sort: "id:desc") {
      data {
        id
        attributes {
          todoText
          createdAt
        }
      }
    }
  }
`;

По-горе ще получим всички най-нови данни, използвайки sort: "id:desc"

Файлът schema.ts ще съдържа схемата за всички graphql заявки

След това импортирайте GETQUERY и useQuery във файла page.tsx:

// src/app/page.tsx
"use client";
import { useEffect, useState } from "react";
import AddTodo from "@/containers/AddTodo";
import TodoList from "@/containers/TodoList";
import { useQuery } from "@apollo/experimental-nextjs-app-support/ssr";
import { GETQUERY } from "@/query/schema";

export default function Home() {
  const [todos, setTodos] = useState<[]>([]);
  const { loading, error, data } = useQuery(GETQUERY, {
    fetchPolicy: "no-cache",
  }); //Fetching all todos
  useEffect(() => {
    setTodos(data?.todos?.data); //Storing all the todos
  }, [data]);

  //rest of the code
}

Тук извлякохме всички задачи от Strapi с помощта на useQuery и ги съхранихме в състояние todos. Отидете до http://localhost:3000 и трябва да получите изход, подобен на този по-долу:

Strapi по подразбиране задава максималното количество извлечени данни на 10. За да промените това, вижте документацията на Оригинал на Strapi.

Създаване на задача

Преди да можем да отправим заявка към Strapi за добавяне на задача, трябва да направим следното:

  • Кликнете върху Content-Type Builder от страничната навигационна лента и върху бутона Редактиране
  • Кликнете върху РАЗШИРЕНИ НАСТРОЙКИ, махнете отметката от Чернова и публикуване и щракнете върху Край. › Strapi има настройка по подразбиране, която позволява на администраторите да преглеждат всяко изпратено съдържание, като им предоставя възможност да го прегледат и оценят.
  • След това щракнете върху иконата за редактиране на todoText.
  • Щракнете върху РАЗШИРЕНИ НАСТРОЙКИ, отметнете Задължително поле, щракнете върху бутона Край и натиснете бутона Запазване горе вдясно .

След като това е направено, вече можем да създадем задача. Отворете файла schema.ts и добавете схемата, за да добавите задача.

// src/query/schema.ts
import { gql } from "@apollo/client";

//The rest of the code

export const ADDMUT = gql`
  mutation createTodo($todoText: String) {
    createTodo(data: { todoText: $todoText }) {
      data {
        id
        attributes {
          todoText
          createdAt
        }
      }
    }
  }
`;

За да добавим задача, ще импортираме схемата ADDQUERY от schema.ts и функцията useMutation от apollo/client.

// src/app/page.tsx

//The rest of the code

import { useMutation } from "@apollo/client";
import { GETQUERY, ADDMUT } from "@/query/schema";

export default function Home() {
  const [todos, setTodos] = useState<[]>([]);
  const [createTodo] = useMutation(ADDMUT);
  const { loading, error, data } = useQuery(GETQUERY, {
    fetchPolicy: "no-cache",
  }); //Fetching all todos
  useEffect(() => {
    console.log(data?.todos?.data);
    setTodos(data?.todos?.data); //Storing all the todos
  }, [data]);
  const addTodo = async (todoText: string) => {
    await createTodo({
      //Creating a new todo
      variables: {
        todoText: todoText, //Passing the todo text
      },
    }).then(({ data }: any) => {
      setTodos([...todos, data?.createTodo?.data] as any); //Adding the new todo to the list
    });
  };

  //The rest of the code.
}

Редактиране на задача

За да актуализираме данни в Strapi с помощта на Graphql, ние ще използваме id на конкретната задача, която актуализираме. Отворете файла schema.ts и добавете мутацията на graphql за функцията за актуализиране.

// src/query/schema.ts
import { gql } from "@apollo/client";

//The rest of the code

export const UPDATEMUT = gql`
  mutation updateTodo($id: ID!, $todoText: String!) {
    updateTodo(id: $id, data: { todoText: $todoText }) {
      data {
        id
        attributes {
          todoText
          createdAt
        }
      }
    }
  }
`;

Сега импортирайте схемата UPDATEMUT във файла pages.tsx.

// src/app/page.tsx
//The rest of the code

import { GETQUERY, ADDMUT, UPDATEMUT } from "@/query/schema";
export default function Home() {
  const [todos, setTodos] = useState<[]>([]);
  const [createTodo] = useMutation(ADDMUT);
  const [updateTodo] = useMutation(UPDATEMUT);

  //The rest of the code

  const editTodoItem = async (todo: any) => {
    const newTodoText = prompt("Enter new todo text or description:");
    if (newTodoText != null) {
      await updateTodo({
        //updating the todo
        variables: {
          id: todo.id,
          todoText: newTodoText,
        },
      }).then(({ data }: any) => {
        const moddedTodos: any = todos.map((_todo: any) => {
          if (_todo.id === todo.id) {
            return data?.updateTodo?.data;
          } else {
            return _todo;
          }
        });
        setTodos(moddedTodos);
      });
    }
  };

  //The rest of the code
}

Функцията editTodoItem редактира задача. Той подканва потребителя да въведе новия текст на задачата. При щракване върху OK в диалоговия прозорец за подкана, той редактира задачата със задачата id.

Изтриване на задача

Стигнахме до последния раздел в нашата заявка за CRUD. В този раздел ще изтрием задача, използвайки идентификатора на задача. Отворете файла schema.ts и добавете DELETEMUT.

// src/query/schema.ts
import { gql } from "@apollo/client";

//The rest of the code

export const DELETEMUT = gql`
  mutation deleteTodo($id: ID!) {
    deleteTodo(id: $id) {
      data {
        id
        attributes {
          todoText
          createdAt
        }
      }
    }
  }
`;

Импортирайте схемата DELETEMUT в pages.tsx.

// src/app/page.tsx
//The rest of the code

import { GETQUERY, ADDMUT, UPDATEMUT, DELETEMUT } from "@/query/schema";
export default function Home() {
  const [todos, setTodos] = useState<[]>([]);
  const [createTodo] = useMutation(ADDMUT);
  const [updateTodo] = useMutation(UPDATEMUT);
  const [deleteMUT] = useMutation(DELETEMUT);

  //The rest of the code
  const deleteTodoItem = async (todo: any) => {
    if (confirm("Do you really want to delete this item?")) {
      await deleteMUT({
        //Deleting the todo
        variables: {
          id: todo.id,
        },
      }).then(({ data }: any) => {
        const newTodos = todos.filter((_todo: any) => _todo.id !== todo.id);
        setTodos(newTodos as any);
      });
    }
  };
  //The rest of the code
}

Вземете пълния изходен код от секцията с ресурси

Функцията deleteTodoItem приема обекта todo да бъде изтрит в todo arg. Първо потвърждава дали потребителят иска да изтрие задачата, ако да, продължава да изтрива задачата. Това ще накара Strapi да изтрие задачата с идентификатора в своята база данни. След това филтрираме изтритите задачи и задаваме филтрирания резултат като нови задачи в състояние на задачи.

Ресурси

Можете да намерите изходния код на приложението тук:

Можете също да решите да прочетете повече за Strapi и graphql, като използвате връзките:

Заключение

Ура 🎉, стигнахме до края на тази статия. Статията показва как да интегрирате Strapi в NextJS чрез изграждане на приложение за задачи. Чувствайте се свободни да проверите приложението на различните си машини и да коментирате всички грешки, ако възникнат.