React Router学习报告

放上视频链接:[b站转载视频][a] youtube 课程文件github

准备知识

  • 引入代码

    1
    2
    3
    4
    import {
    createBrowserRouter,
    RouterProvider,
    } from "react-router-dom";
  • 基础结构,这里可以看到我们使用<Main />包裹了里面的内容,这里的Main组件包括了一些基础性内容,比如页面头部和底部。包裹起来进行路由跳转时,里面的组件也会拥有这些内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const router = createBrowserRouter([
    {
    path: "/",
    element: <Main />,
    loader: mainLoader,
    errorElement: <Error />,
    children: [
    {
    index: true,
    element: <Dashboard />,
    loader: dashboardLoader,
    errorElement: <Error />
    },
    {
    path: "logout",
    action: logoutAction
    }
    ]
    },

    ])
  • 根据上面的例子的元素实例,和数据函数,请千万千万记住,在浏览器本地存储的时候密钥为key,值为value(字符串,加上双引号,我在这里debug快一个小时。。)如果数据加载异常不会有任何错误提示,路由会跳转到<Error />

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    // loader
    export function mainLoader(){
    const userName = fetchData("userName");
    return {userName}
    }

    const Main = () => {

    const {userName} = useLoaderData()

    return (
    <div className='layout'>
    <Nav userName={userName} />
    <Outlet />
    <img src={wave} alt="" />
    </div>
    )
    }

    export default Main
  • fetchData函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Loacl Storage
    export const fetchData = (key) => {
    return JSON.parse(localStorage.getItem(key));
    };

    //delete item
    export const deleteItem = ({key}) => {
    return localStorage.removeItem(key)
    }

小知识

PS : 内容太多了,只能补充一些个人认为比较有用的知识了

  • 使用lebel的htmlFor属性和input中的id属性对应,之后可以用于获取数据

    1
    2
    3
    4
    5
    6
    <label htmlFor="newExpense">Expense Name</label>
    <input
    type="text"
    name="newExpense"
    id="newExpense"
    />
  • 使用input

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <input type="hidden" name="_action" value="deleteExpense" />
    <input type="hidden" name="expenseId" value={expense.id} />
    // 把input隐藏,将名称改为_action,之后通过一下代码获取分步处理
    export async function dashboardAction({request}){
    const data = await request.formData();
    const {_action, ...values} = Object.fromEntries(data);
    // 下面使用判断语句判断_action,然后try-catch,下面给出一个例子
    if(_action === "deleteExpense"){
    try{
    deleteItem({
    key: "expenses",
    id: values.expenseId
    })
    return toast.success("Expense deleted!")
    } catch(e){
    throw new Error("There was a problem deleting your expense.")
    }
    }
    // 请万分注意,我debug了快一个小时,因为id传递的参数写错了,必须和name相对应,之前不小心写成expenses直接找半天
    }
  • 使用fetcher

    1
    2
    3
    4
    5
    6
    7
    const fetcher = useFetcher();
    // 使用fetcher
    <fetcher.Form method="post" className="grid-sm" ref={formRef}>
    </fetcher.Form>
    // 把表单改为上面代码
    // 可以通过这个检查状态idle loading submitting
    const isSubmitting = fetcher.state === "submitting"
  • 使用Ref

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 使用Ref来检测
    const formRef = useRef();
    const focusRef = useRef();
    useEffect(() => {
    if(!isSubmitting){
    // clear form
    formRef.current.reset()
    // reset focus
    focusRef.current.focus()
    }
    },[isSubmitting])
    // 通过这个代码对提交的表单进行内容清空和重新focus,focusRef放到需要的input中

脑抽小bug

  • map使用

    1
    2
    3
    4
    {budgets.map((budget) => (
    <BudgetItem key={budget.id} budget={budget} />
    ))}
    // returning a valid JSX element inside map(),如果使用{}需要返回jsx元素,向上面这样写需要使用()

[a]: Part03-Layouts & Actions_哔哩哔哩_bilibili