当我试图根据 useParams id 从 redux state 数组中找到一个值时,redux useselector return undefined

redux useselector return undefined when i tried to find a value from redux state array according to useParams id

CodeSandbox link

我正在尝试创建一个演示添加 post 应用程序,它有 PostsList.jsxSinglePostPage.jsx 组件。我在此应用程序中使用 redux-toolkitaxiosreact-router-dom@6JSONplaceholder。每个 post 部分都有一个 View Post Link 按钮来查看完整的 post.

PostList.jsx

const PostsList = () => {
  const posts = useSelector((state) => state.posts.entities);
      const renderedPosts = posts.map((post) => (
        <article key={post.id}>
          <h3>{post.title}</h3>
          <p> {post.body.substring(0, 100)} </p>
          <Link to={`posts/${post.id}`}> View Post </Link>
        </article>
      ));
    
      return (
        <section>
          <h2>Posts</h2>
          {renderedPosts}
        </section>
      );
    };

我的PostSlice.js文件:

const initialState = {
  entities: [],
  status: 'idle',
  error: null,
};

export const fetchPosts = createAsyncThunk('posts/fetchPosts', async () => {
  const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
  return response.data;
});

const postsSlice = createSlice({
  name: 'posts',
  initialState,
  reducers: {
    //omit the reducer functions
  },
  extraReducers(builder) {
    builder
      .addCase(fetchPosts.pending, (state) => {
        state.status = 'loading';
      })
      .addCase(fetchPosts.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.entities = state.entities.concat(action.payload);
      })
      .addCase(fetchPosts.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
});

我在 SinglePostPage.jsx components.The PostSlist 组件正常工作时遇到问题。但是 useSelector return undefind 当我试图根据 useParams 钩子给出的 id 从 redux 状态数组中获取值时。

SinglePostPage.jsx

 const SinglePostPage = () => {
      const { postId } = useParams();
      console.log('postId:', postId);
      // postId: 1
      const post = useSelector((state) => state.posts.entities.find(post=> post.id === postId));
      console.log('post:', post);
      // post: undefined
      
      if (!post) {
        return (
          <div>
            <BtnLink to="/">Posts</BtnLink>
            <h1>
              The post doesn't found. Please, go back to the posts section.
            </h1>
          </div>
        );
      }
      return (
        <div>
          <div className="flex justify-between mb-7">
            <BtnLink to="/">Posts</BtnLink>
            <BtnLink to={`/editPost/${postId}`}>Edit Post</BtnLink>
          </div>
          <div>
            <h1>{post.title}</h1>
            <p>{post.body}</p>
          </div>
        </div>
      );
    };
    export default SinglePostPage;

而不是 postId,如果我使用 integer,那么我会得到特定 id

的值
const post = useSelector((state) => state.posts.entities.find(post=> post.id === 1));
console.log('post:', post);
// post: {data}

我该如何解决这个问题...???

问题是路由参数总是字符串,而 post id 属性 是一个数字。

{
  "userId": 1,
  "id": 1, // <-- number type
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum
    rerum est autem sunt rem eveniet architecto"
},

这就是为什么使用数字直接匹配 (state.posts.entities.find(post=> post.id === 1)) 对您有效。

您在按 ID 搜索匹配项 post 时使用了严格 (===) 相等性。

const { postId } = useParams();
const post = useSelector((state) =>
  state.posts.entities.find((post) => post.id === postId)
);

post.id是数字,postId是字符串,所以等式检查returns false,因为类型不一样。

要解决这个问题,您可以使用松散相等来完成类型转换:

const { postId } = useParams();
const post = useSelector((state) =>
  state.posts.entities.find((post) => post.id == postId) // 1 == "1" -> true
);

或者更好地将 post id 转换为字符串并保持严格相等:

const { postId } = useParams();
const post = useSelector((state) =>
  state.posts.entities.find((post) => String(post.id) === postId) // "1" === "1" -> true
);