Redux useSelect 没有按预期更新

Redux useSelect doesn't get updated as expected

我正在做一个小的概念验证项目,使用 React 和 Redux,以及 useSelector 和 useDispatch 挂钩。我正在尝试异步获取一些数据,为此我使用了 thunk。我想我在概念上遗漏了一些东西。即使我的状态按预期工作,我也无法使用 useSelector 从 api 获取数据。

这是代码。我的行动:

import axios from "axios";

export const API_FETCH_POSTS = 'API_FETCH_POSTS';

export const fetchPosts = (postId) => { // to simulate post request
    return (dispatch) => {

        let baseUrl = 'https://jsonplaceholder.typicode.com/';
        let postFix = 'comments?postId=';
        let url = `${baseUrl}${postFix}${postId}`;

        axios.get(url)
            .then(response => {
                const data = response.data;
                console.log(JSON.stringify(data)); // work!
                dispatch(fetchPostsSuccess(data));
            });
    }
};

const fetchPostsSuccess = posts => {
    return {
        type: API_FETCH_POSTS,
        payload: posts
    }
};

我的减速器:

import {API_FETCH_POSTS} from "./apiActions";

const initialState = {
    getPostsReq : {
        posts: [],
    }
};

const apiReducer = (state = initialState, action) => {
    let getPostsReq;
    switch (action.type) {
        case API_FETCH_POSTS:
            getPostsReq = {
                posts: [...state.getPostsReq.posts]
            };

            return {
                ...state,
                getPostsReq
            };
        default: return state;
    }
};

export default apiReducer;

和rootReducer:

import {combineReducers} from 'redux';
import apiReducer from "./api/apiReducer";

export default combineReducers({
    api: apiReducer
})

并存储:

const initialState = {};

const store = createStore(
    rootReducer,
    initialState,
    composeWithDevTools(
        applyMiddleware(thunk)
    )
);

export default store;

我的 React 组件有问题:

function PostContainer(props) {
    const posts = useSelector(state => state.api.getPostsReq.posts);
    const dispatch = useDispatch();

    const logPosts = () => {
        {/*why doesn't this line work???*/}
        console.log(JSON.stringify(posts));
    }

    return (
        <div>
            <button onClick={() => {
                dispatch(fetchPosts(1));
                logPosts();
            }}>Fetch Posts</button>

            <div>
                {/*why doesn't this line work???*/}
                {posts.map(post => <p>{post.body}</p>)}
            </div>
        </div>
    );
}

export default PostContainer;

我希望在我按下按钮后,函数 fetchPosts 被调度,因为我使用 thunk,所以我不应该有任何异步问题。但由于某种原因,我无法使用 useSelector() 挂钩获取我的状态。我既不能渲染状态,也不能在控制台中记录它。

我在这里错过了什么?

如果更方便的话,这里是完整的代码 - https://github.com/JavavaJ/use-select-problem

问题:不存储帖子

你的选择器没问题,问题出在你的减速器上!您发送了一个操作,该操作在 payload:

中有 array 个帖子
const fetchPostsSuccess = posts => {
    return {
        type: API_FETCH_POSTS,
        payload: posts
    }
};

但是当您在 reducer 中响应此操作时,您会完全忽略 payload 而只是 return 您已经拥有的相同帖子:

const apiReducer = (state = initialState, action) => {
    let getPostsReq;
    switch (action.type) {
        case API_FETCH_POSTS:
            getPostsReq = {
                posts: [...state.getPostsReq.posts]
            };

            return {
                ...state,
                getPostsReq
            };
        default: return state;
    }
};

解决方案:从操作中添加帖子

您可以像这样重写您的减速器以使用 Redux immutable update patterns 添加帖子。

const apiReducer = (state = initialState, action) => {
  switch (action.type) {
    case API_FETCH_POSTS:
      return {
        ...state,
        getPostsReq: {
            ...state.getPostsReq,
            posts: [...state.getPostsReq.posts, ...action.payload]
        }
      };
    default:
      return state;
  }
};

使用Redux Toolkit就简单多了!使用该工具包,您可以“改变”减速器中的草稿状态,因此我们不需要复制所有内容。

const apiReducer = createReducer(initialState, {
  [API_FETCH_POSTS]: (state, action) => {
    // use ... to push individual items separately
    state.getPostsReq.posts.push(...action.payload);
  }
});