做网站流量优化都是什么,地方网站域名,徐州专门做网站,wordpress 禁止索引目录加载数据
这一节主要强调 URL、布局和数据 的解耦。
在根模块文件中创建并导出一个加载器函数#xff0c;并配置到路由。
getContacts() 是我们自己封装的数据请求 API#xff0c;新增的数据暂时存储到 localforage。
export async function loader() {const contacts a…加载数据
这一节主要强调 URL、布局和数据 的解耦。
在根模块文件中创建并导出一个加载器函数并配置到路由。
getContacts() 是我们自己封装的数据请求 API新增的数据暂时存储到 localforage。
export async function loader() {const contacts await getContacts();return { contacts };
}路由配置 loader
// 配置 loader
loader: rootLoader,数据渲染使用 内置的 useLoaderData() 方法
const { contacts } useLoaderData();数据写入
提交 HTML 表单时它会在浏览器中引起导航事件就像我们点击某个链接一样。而链接和提交表单的唯一的区别在于请求链接只能更改 URL而表单还可以更改请求方式GET 与 POST和请求体POST 表单数据。
如果没有客户端路由也就是react-router这类的client-side routing浏览器会自动序列化表单数据并以不同的方式发送给服务器。对于POST请求数据会作为请求体request body发送给服务器而对于GET请求数据会作为URLSearchParamsURL查询参数的形式附加在URL上发送给服务器。
React Router的行为与此类似但它不会将请求发送到服务器而是使用客户端路由并将请求发送到路由操作action进行处理。
我们使用 React Router 封装的 Form创建用户。
Form methodpostbutton typesubmitNew/button
/Formexport async function action() {const contact await createContact();return redirect(/contacts/${contact.id}/edit);
}像 loader 一样action 创建后也需要挂载在路由上。action: rootAction。
可以简单的理解为 loader 是需要获取数据时触发的action 则是修改数据时触发的。
创建用户信息使用 Form submit之后我们发现Reat Router 的Form 自动阻止了浏览器发送请求到服务器而是将其发送到我们指定的路由操作action中 。然后自动触发数据重新验证的过程也就意味着所有使用 useLoaderData 钩子的组件都会自动更新并且UI会自动与数据保持同步避免我们使用 useState 、 onSubmit 和 useEffect 这些操作极大地简化了我们的操作。
URL 参数
path: contacts/:contactId,:contactId URL 段。冒号 ( : ) 为“动态段”。动态段将匹配 URL 该位置上的动态变化值如联系人 ID。我们将 URL 中的这些值称为“URL 参数”简称 “params”。这些params将作为键值对传递给加载器loader值将作为 params.contactId 传递可以在 loader上使用。
当然每个组件中的 loader action 等都需要在路由中进行配置而且路由通常都有自己的 laoder 等只不过他们有时可能会相同。
export async function loader({ params }) {const contact await getContact(params.contactId);return { contact };
}export async function Contact() {const { contact } useLoaderData();// ...
}更新数据
inputplaceholderFirstaria-labelFirst nametypetextnamefirstdefaultValue{contact.first}
/如果没有 JavaScript当提交表单时浏览器会创建FormData对象并将其设置为请求的主体body然后将请求发送到服务器。
如前所述React Router 阻止了这种默认行为而是将请求发送到我们自己想要的操作也就是自己在组件中定义的 action中同时包括FormData。表单中的每个字段都可以通过 formData.get(name) 访问。
这里还使用Object.fromEntries将数据全部收集到一个对象中这正是后面自定义的 updateContact 函数想要的。
export async function action({ request, params }) {const formData await request.formData();const updates Object.fromEntries(formData);await updateContact(params.contactId, updates);return redirect(/contacts/${params.contactId});
}loader和action都可以返回Response因为它们都收到了Request!。
redirect辅助函数只是为了更方便地返回response告诉应用程序更改位置。
活动链接样式
NavLinkto{contacts/${contact.id}}className{({ isActive, isPending }) isActive? active: isPending? pending: }NavLink 是一种特殊的 Link 它知道自己是否处于 “激活”、待定 或 过渡 状态。当用户访处于NavLink指定的URL时isActive将为true。当链接即将被激活时数据仍在加载中 isPending 将为 true。
loading 界面
当用户浏览应用时React Router 会在为下一页加载数据时保留旧页面。也就是说这种数据模型具有客户端缓存因此第二次导航到之前已经访问过的路由时速度会很快。
useNavigation返回当前导航状态可以是idle | submitting | loading
const navigation useNavigation();
// ...
navigation.state loading ? loading : 删除数据
FormmethodpostactiondestroyonSubmit{(event) {if (!confirm(Please confirm you want to delete this record.)) {event.preventDefault();}}}
button typesubmitDelete/button
/Formaction 指向 destroy 。与 Link to 一样 Form action 也可以接收一个相对值。由于表单是在 contact/:contactId 中呈现的因此点击 destroy 的相对操作将把表单提交到 contact/:contactId/destroy 所以我们只需要在 contact/:contactId/destroy 路由下指定删除操作即可。比如
export async function action({ params }) {await deleteContact(params.contactId);return redirect(/);
}{path: contacts/:contactId/destroy,action: destroyAction,
},详细说明当用户点击提交按钮时
Form 会阻止浏览器向服务器发送新 POST 请求的默认行为而是通过客户端路由创建一个 POST 请求来模拟浏览器的行为Form actiondestroy 匹配道路新路由 contacts/:contactId/destroy 并向其发送请求在操作重定向后React Router 会调用页面上所有数据的loader以获取最新值这就是 “重新验证”。 useLoaderData 返回新值并导致组件更新
捕获错误
export async function action({ params }) {await deleteContact(params.contactId);throw new Error(oh dang!);return redirect(/);
}虽然我这个操作中 return redirect(/); 根本就不会执行但这只是为了说明如何捕获错误。
这样操作完成之后发现直接如今了错误页必须刷新才会重新加载恢复正常显示。
因此需要在路由中进行捕获
{path: contacts/:contactId/destroy,action: destroyAction,errorElement: divOops! There was an error./div,
},因为销毁路由有自己的errorElement并且是根路由的子路由因此错误会在此处路由而不是根路由上呈现。这些错误会以最近的 errorElement 冒泡。只要在根路径上有一个添加多少都行。
索引路由
如果在父路由的路径上 Outlet 由于没有子路由匹配所以没有任何内容可以呈现。可以把索引路由看作是填补这一空白的默认子路由。
定义一个索引路由的页面模块 index。然后在子路由上添加
{ index: true, element: Index / },这将告诉路由当用户位于父路由的确切路径时路由器将匹配并呈现此路由以保证在 Outlet 中没有其他子路由需要呈现时页面不为空。
导航
用一个取消功能来说明。
const navigate useNavigate();buttontypebuttononClick{() {navigate(-1);}}
Cancel/button这里的 button typebutton 虽然看似多余却是防止按钮提交表单的 默认 HTML 行为。所以按钮上没有event.preventDefault。 以上说明中路由
// 创建路由
const router createBrowserRouter([{path: /,// 将Root设置为根路由elementelement: Root/,// 将ErrorPage设置为根路由上的errorElementerrorElement: ErrorPage/,// 配置 loaderloader: rootLoader,// 配置 actionaction: rootAction,// 子路由children: [{ index: true, element: Index / },{path: contacts/:contactId,element: Contact/,loader: contactLoader},{path: contacts/:contactId/edit,element: EditContact/,loader: contactLoader,action: editAction},{path: contacts/:contactId/destroy,action: destroyAction,errorElement: divOops! There was an error./div,},]},
])