Reputation: 4898
I am fetching data using axios and then map state to props with redux but I have a problem. If I dispatch the action in componentDidUpdate()
the action execute indefinitely and if I used the constructor(props)
I get undefined value for props
I tried also componentDidMount
but I get undefined value for probs. Is there a way to dispatch the action using react components ?
I get the correct data from state
in the second render.
import React, { Component } from 'react'
import {connect} from 'react-redux'
import { getUserPosts } from '../../actions'
class UserPosts extends Component {
//UNSAFE_componentWillMount() {
//}
constructor(props) {
super(props);
console.log(props);
}
componentDidUpdate() {
//this.props.dispatch(getUserPosts(this.props.user_reducer.login?.user._id));
}
showUserPosts = (user) => (
Array.isArray(user.userPosts) ?
user.userPosts.map((item, i) => (
<tr key={i}>
<td>{i}</td>
<td>author</td>
<td>date</td>
</tr>
))
: null
)
render() {
let user = this.props.user_reducer;
//console.log(user.userPosts);
return (
<div>
<div className="user_posts">
<h4>Your reviews:</h4>
<table>
<thead>
<tr>
<th>Name</th>
<th>Author</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{this.showUserPosts(user)}
</tbody>
</table>
</div>
</div>
)
}
}
function mapStateToProps(state) {
//console.log(state);
return {
user_reducer: state.user_reducer
}
}
export default connect(mapStateToProps)(UserPosts)
action:
export function getUserPosts(userId) {
const req = axios.get(`/api/user_posts?user=${userId}`)
.then(res => res.data);
return {
type: 'GET_USER_POSTS',
payload: req
}
}
reducer:
export default function(state = {}, action) {
switch(action.type) {
case 'USER_LOGIN':
return {...state, login: action.payload}
case 'USER_AUTH':
return {...state, login: action.payload}
case 'GET_USER_POSTS':
return {...state, userPosts: action.payload}
default: return state;
}
}
Upvotes: 0
Views: 1617
Reputation: 281676
The correct place to dispatch an action is in componentDidMount. However since your data fetch is async, you must maintain a loading state in your reducer till your data is fetched
export default function(state = {isPostLoading: true}, action) {
switch(action.type) {
case 'USER_LOGIN':
return {...state, login: action.payload}
case 'USER_AUTH':
return {...state, login: action.payload}
case 'GET_USER_POSTS':
return {...state, userPosts: action.payload, isPostLoading: false}
default: return state;
}
}
class UserPosts extends Component {
constructor(props) {
super(props);
console.log(props);
}
componentDidMount() {
this.props.dispatch(
getUserPosts(this.props.user_reducer.login?.user._id)
);
}
componentDidUpdate(prevProps) {
if(this.props.user_reducer.login?.user._id !== prevProps.user_reducer.login?.user._id) {
this.props.dispatch(getUserPosts(this.props.user_reducer.login?.user._id));
}
}
showUserPosts = (user) => (
Array.isArray(user.userPosts) ?
user.userPosts.map((item, i) => (
<tr key={i}>
<td>{i}</td>
<td>author</td>
<td>date</td>
</tr>
))
: null
)
render() {
let user = this.props.user_reducer;
if(user.isPostLoading) {
return <div>Loading....</div>
}
return (
<div>
<div className="user_posts">
<h4>Your reviews:</h4>
<table>
<thead>
<tr>
<th>Name</th>
<th>Author</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{this.showUserPosts(user)}
</tbody>
</table>
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
user_reducer: state.user_reducer
}
}
export default connect(mapStateToProps)(UserPosts)
Upvotes: 1