连接action creators、reducers与redux-thunk后组件不显示数据
Hey there! Let's figure out why your toilet data isn't showing up in your component even though you can see it in the Chrome console. Based on the code snippet you shared and common Redux gotchas, here are the key areas to check:
1. Make sure you're handling async actions with middleware
Since you're using axios (an async call), plain Redux can't handle action creators that return functions. You'll need to set up redux-thunk (or another async middleware) in your store configuration. Here's how to do that:
// In your store setup file (e.g., store.js) import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducers'; // Apply thunk middleware to handle async actions const store = createStore(rootReducer, applyMiddleware(thunk));
Then update your action creator to return an async function that dispatches the action once the API call resolves:
// Your action creator file import axios from 'axios'; const ROOT_URL = `https://toilets.freska.io/toilets`; export const FETCH_TOILETS = 'FETCH_TOILETS'; export const fetchToilets = () => async (dispatch) => { try { const response = await axios.get(ROOT_URL); // Dispatch the action with the fetched data dispatch({ type: FETCH_TOILETS, payload: response.data }); } catch (error) { console.error('Failed to fetch toilets:', error); } };
2. Verify your reducer is updating state correctly
Your reducer needs to properly handle the FETCH_TOILETS action and return a new state object (never mutate state directly). Example reducer:
// toiletsReducer.js import { FETCH_TOILETS } from '../actions'; const initialState = { toilets: [] // Initialize with an empty array }; export default function toiletsReducer(state = initialState, action) { switch (action.type) { case FETCH_TOILETS: // Return a new state object with the fetched toilets return { ...state, toilets: action.payload }; default: return state; } }
Also, make sure this reducer is combined into your root reducer if you're using multiple reducers:
// rootReducer.js import { combineReducers } from 'redux'; import toiletsReducer from './toiletsReducer'; export default combineReducers({ toilets: toiletsReducer // This defines the path in your Redux state });
3. Check if your component is connected to Redux correctly
You need to use connect from react-redux to map Redux state to component props and dispatch actions. Here's how to set that up:
// Your component file import React, { Component } from 'react'; import { connect } from 'react-redux'; import { fetchToilets } from './actions'; class ToiletsList extends Component { // Fetch data when the component mounts componentDidMount() { this.props.fetchToilets(); } render() { const { toilets } = this.props; // Handle loading state while data is fetched if (toilets.length === 0) { return <p>Loading toilets...</p>; } // Render the list of toilets return ( <div className="toilets-list"> {toilets.map(toilet => ( <div key={toilet.id} className="toilet-item"> <h3>{toilet.name}</h3> <p>Address: {toilet.address}</p> </div> ))} </div> ); } } // Map Redux state to component props const mapStateToProps = state => ({ // Adjust the path based on your root reducer setup toilets: state.toilets.toilets }); // Connect the component to Redux and inject the fetchToilets action export default connect(mapStateToProps, { fetchToilets })(ToiletsList);
4. Confirm you're rendering data correctly
- Double-check that the API response structure matches what you're expecting. If the data is nested (e.g.,
response.data.datainstead ofresponse.data), update thepayloadin your action creator to point to the correct array. - Ensure you're using a unique
keyprop for each item in your list (React requires this for efficient rendering). - Make sure you're not accidentally rendering an empty array or undefined value (use the loading state check like in the example above).
5. Verify the action is being dispatched
Use Redux DevTools (if you have it installed) to check if the FETCH_TOILETS action is being triggered, and if the payload contains the correct data. If the action isn't showing up, you might have forgotten to call this.props.fetchToilets() in your component's lifecycle method (like componentDidMount).
内容的提问来源于stack exchange,提问作者intercoder

