Еще один фреймворк?
В Next.js страница - это компонент React, экспортированный из файла .js, .jsx, .ts или .tsx в папке pages.
Каждая страница связана с маршрутом на основе имени файла.
function About() {
return <div>About</div>
}
export default Aboutpages/blog/[slug].js → /blog/:slug
pages/[username]/settings.js → /:username/settings
import Link from 'next/link'
function Home() {
return (
<ul>
<li>
<Link href="/">
<a>Home</a>
</Link>
</li>
<li>
<Link href="/about">
<a>About Us</a>
</Link>
</li>
<li>
<Link href="/blog/hello-world">
<a>Blog Post</a>
</Link>
</li>
</ul>
)
}
export default Homeimport { useRouter } from 'next/router'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/about')}>
Click me
</button>
)
}import App from 'next/app'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}function Page({ data }) {
// Render data...
}
// This gets called on every request
export async function getServerSideProps() {
// Fetch data from external API
const res = await fetch(`https://.../data`)
const data = await res.json()
// Pass data to the page via props
return { props: { data } }
}
export default Pagefunction Blog({ posts }) {
return (
<ul>
{posts.map((post) => (
<li>{post.title}</li>
))}
</ul>
)
}
export async function getStaticProps() {
// Call an external API endpoint to get posts
const res = await fetch('https://.../posts')
const posts = await res.json()
// By returning { props: { posts } }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
export default Blogexport async function getStaticPaths() {
const res = await fetch('https://.../posts')
const posts = await res.json()
const paths = posts.map((post) => ({
params: { postId: post.id },
}))
return {
paths,
};
}Можно писать backend!
Любой файл внутри папки pages/api сопоставляется
с /api/* и будет рассматриваться как эндпоинт сервера, а не страница.
Эндпоинты не включаются в бандл клиента.
export default function handler(req, res) {
res.status(200).json({ name: 'John Doe' })
}Состояние Интерфейса (Client State) — состояние в котором есть смысл только в интерфейсе пользователя, оно нужно для управления интерактивными частями приложения (к примеру, открытие модального окна — modal isOpen)
Кэш Сервера (Server State) — состояние которое размещено на сервере для быстрого доступа к нему на клиенте (к примеру — данные пользователя).
import { QueryClient, QueryClientProvider } from 'react-query'
// Create a client
const queryClient = new QueryClient()
function App() {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<Todos />
</QueryClientProvider>
)
} import { useQuery } from 'react-query'
const fetchTodoList = () => fetchTodos();
function Todos() {
const { isLoading, isFetching, isError, data, error } = useQuery('todos', fetchTodoList)
if (isLoading) {
return <span>Loading...</span>
}
if (isFetching) {
return <span>Fetching...</span>
}
if (isError) {
return <span>Error: {error.message}</span>
}
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
} // An individual todo
useQuery(['todo', 5], ...)
// queryKey === ['todo', 5]
// Query Keys are hashed deterministically!
// This means that no matter the order of keys in objects,
// all of the following queries are considered equal:
useQuery(['todos', { status, page }], ...)
useQuery(['todos', { page, status }], ...)
useQuery(['todos', { page, status, other: undefined }], ...)
// The following query keys, however, are not equal.
// Array item order matters!
useQuery(['todos', status, page], ...)
useQuery(['todos', page, status], ...)
useQuery(['todos', undefined, page, status], ...)
const prefetchTodos = async () => {
// The results of this query will be cached like a normal query
await queryClient.prefetchQuery('todos', fetchTodos)
}import { useMutation } from 'react-query';
function App() {
const { isLoading, isError, isSuccess, mutate } = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
<div>
{isLoading ? 'Adding todo...'
: (
<>
{isError ? (<div>An error occurred: {mutation.error.message}</div>)
: null}
{isSuccess ? <div>Todo added!</div> : null}
<button
onClick={() => {
mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
} // Invalidate every query in the cache
queryClient.invalidateQueries()
// Invalidate every query with a key that starts with `todos`
queryClient.invalidateQueries('todos') import { useMutation, useQueryClient } from 'react-query'
const queryClient = useQueryClient()
// When this mutation succeeds, invalidate any queries
// with the `todos` or `reminders` query key
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos')
queryClient.invalidateQueries('reminders')
},
}) import { useMutation, useQueryClient } from 'react-query'
const queryClient = useQueryClient()
// When this mutation succeeds, invalidate any queries
// with the `todos` or `reminders` query key
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries('todos')
queryClient.invalidateQueries('reminders')
},
}) const useMutateTodo = () => {
return useMutation(editTodo, {
// Notice the second argument is the variables object
// that the `mutate` function receives
onSuccess: (data) => {
queryClient.setQueryData(['todo', { id: data.id }], data)
},
})
}