I have a functional component that fetches data from an api using redux.
const useFetching = (someFetchActionCreator) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(someFetchActionCreator());
}, [])
}
The component:
export function Trips(props) {
const trips = useSelector(state => state.trips);
useFetching(fetchTrips)
...
...
}
The thunk:
export const fetchTrips = () => (dispatch) =>
axios.get("/api/v1/trips")
.then(response => dispatch(addTrips(response.data)))
export const addTrips = trips => ({
type: ADD_TRIPS,
payload: trips
})
The reducer:
function tripsReducer(state = INITIAL_STATE, action) {
console.log(action)
if (action.type === ADD_TRIPS) {
return Object.assign({}, state, {
trips: state.trips.concat(action.payload)
});
}
return state
}
My reducer is called. How can I update the UI after the fetched data have been dispatched? My render is not called again.
1st option: Using hooks
You are actually using React and react-redux hooks. Make sure you use the object trips later in your component. Here is a sample using your code:
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchTrips } from '../tripsActions';
const useFetching = (someFetchActionCreator) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(someFetchActionCreator());
}, []);
}
export function Trips(props) {
const trips = useSelector(state => state.trips);
useFetching(fetchTrips);
return (
<div>
<p>Total trips: {trips.length}</p>
</div>
);
}
2nd option: Using connect
This was the way to connect to the Redux store state before they introduced the hooks.
As you are using react-redux this can be easily done by using the connect() function. You should also provide a mapStateToProps() function to select the part of the data from the store that your component needs and a mapDispatchToProps() function to have access to the actions to be dispatched.
This is how your Trips component would look like with this approach:
import React from 'react';
import { connect } from 'react-redux';
import { fetchTrips } from '../tripsActions';
const mapStateToProps = (state) => {
return {
// will be available as props.trips
trips: state.trips
}
}
const mapDispatchToProps = (dispatch) => {
return {
// will be available as props.fetch()
fetch: () => dispatch(fetchTrips)
}
}
const function Trips(props) {
this.props.fetch();
// some other code. Example:
return (
<div>
<p>Total trips: {this.props.trips.length}</p>
</div>
);
}
export default connect(mapStateToProps)(Trips);
mapStateToProps() receives the Redux store state and returns an object whose fields will be available as props in your component. As you already use props.trips I simply mapped that field to the updated value of the Redux state's trips field.
The call to connect() with your component gives you a connected component. And that latter should be exported rather than the original component. It will not create another component so you will continue to use the Trips component normally.
Now your component will be re-rendered as its props are being updated.
You can have a look at the react-redux documentation to better understand the use of connect() and mapStateToProps() and mapDispatchToProps() functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With