Redxu(RTK) 基础 性能与数据范式化 6.1 添加用户页面

通过第5节,我们已经学会了使用thunk处理异步数据的整体流程了,在此基础上。
通过第6节,我们将要学会:

  • 如何使用 createSelector 创建记忆化的 selector 函数
  • 优化组件渲染性能的方法
  • 如何使用 createEntityAdapter 来存储和更新范式化数据
简介

在第五节:异步逻辑与数据请求中,我们讲解了如何编写异步 thunks 从服务端 API 获取数据,如何处理异步请求 state 的开发模式,以及如何使用 selector 函数对从 Redux state 中读取数据的逻辑进行封装。
在本节中,我们将研究优化方法来确保我们的应用具有较好性能,以及用于自动处理 store 中数据常见更新的技术。
到目前为止,我们的大部分功能都以 posts 的特点为中心。接下来,我们将为这个应用添加几个新部分,添加这些之后,我们将看一看构建事物的具体细节,并讨论到目前为止我们构建的一些缺陷以及我们应该如何对其进行改进。

添加用户页面

让我们添加一个页面来显示所有用户列表,添加另一个页面来显示特定用户的所有帖子。(类似原来的PostsList组件嘛。。。)
先创建一个UserList组件,在他内部,我们也使用useSelector 从store获取数据并渲染成对应的用户列表,其中用户包含一个跳转到其各自页面的链接:
看下方代码捏!

//这是注释,显示文件路径捏:/src/features/users/UserList.tsx
import React from 'react'
import { useSelector } from 'react-redux'
import { Link } from 'react-router-dom'
import { selectAllUsers } from './usersSlice'

export const UsersList = () => {
  const users = useSelector(selectAllUsers)

  const renderedUsers = users.map(user => (
    <li key={user.id}>
      <Link to={`/users/${user.id}`}>{user.name}</Link>
    </li>
  ))

  return (
    <section>
      <h2>Users</h2>

      <ul>{renderedUsers}</ul>
    </section>
  )
}

当然不要忘记对应编写selectAllUsers 这个selector捏,另外再预先添加一个selectUserById,等会会用到的捏!

export const selectAllUsers = (state: RootState) => {
  return state.users.users
};
export const selectUserById = (state: RootState, userId:string|undefined) =>
  state.users.users.find(user => user.id === userId)

接下来,我们将添加 , 类似于我们的 ,从路由中获取 userId 参数,额,注意一点,我使用的react-router版本和文档版本不一样,所以我的代码和文档版本有些微区别捏!另外我还要啰嗦一下呢,要一直使用类型约束过的useSelector和useDispatch呢!

//这是注释,显示文件路径捏:/src/features/users/UserPage.tsx
import React from "react";
import { useSelector } from "react-redux";
import { Link } from "react-router-dom";
import { useParams } from "react-router";
import { selectUserById } from "../users/usersSlice";
import { selectAllPosts } from "../posts/postsSlice";
import { useAppSelector } from "../../app/hooks";

export const UserPage = ({}) => {
  const { userId } = useParams();

  const user = useAppSelector((state) => selectUserById(state, userId));

  const postsForUser = useAppSelector((state) => {
    const allPosts = selectAllPosts(state);
    return allPosts.filter((post) => post.user === userId);
  });

  const postTitles = postsForUser.map((post) => (
    <li key={post.id}>
      <Link to={`/posts/${post.id}`}>{post.title}</Link>
    </li>
  ));

  return (
    <section>
      <h2>{user?.name}</h2>

      <ul>{postTitles}</ul>
    </section>
  );
};

正如我们之前所见,我们可以通过调用 useSelector 或从 props 中获取数据,并在另一个 useSelector 中使用它来帮助决定从 store 中获取哪些内容。
这里我们的版本没使用props,原始文档版本如下:

export const UserPage = ({ match }) => {
  const { userId } = match.params
//省略其他内容,仅仅为了不发生歧义,可见文档内容使用了match这个prop传入数据呢

上面的话的意思就是,我们在使用useSelector的时候可以动态的接受prop或者是其他数据来用于帮助编写useSelector接受的selector内部的逻辑。
比如外部prop传入某个值为真,那么某个selector内部可以有这样一条,我只选取store中某个数据切片中某个值为真的数据并返回这些数据呢。
中为这些组件添加路由,注意因为我用了新版本的react-router,语法有些不同呢!

//这是注释,显示文件路径捏:/src/App.tsx
 <Routes>
          <Route
            path="/"
            element={
              <div>
                <AddPostForm></AddPostForm>
                <PostList />
              </div>
            }
          />
          <Route
            path="/posts/:postId"
            element={<SinglePostPage></SinglePostPage>}
          ></Route>
          <Route
            path="/editPost/:postId"
            element={<EditPostForm></EditPostForm>}
          ></Route>
             <Route
            path="/users"
            element={<UsersList></UsersList>}
          ></Route>
            <Route
            path="/users/:userId"
            element={<UserPage></UserPage>}
          ></Route>
          <Route path="*" element={<div>This is nowhere</div>} />
        </Routes>

然后在 中添加一个用于链接到 /users 的 tab ,使我们能够点击并跳转到

//这是注释,显示文件路径捏:/src/components/Navbar.tsx
   <div className="navLinks">
            <Link to="/">文章列表</Link>
            <Link to="/users">用户列表</Link>
          </div>
posted @ 2023-03-14 16:18  刘老六  阅读(31)  评论(0编辑  收藏  举报