2

I'm trying to get my component load data before rendering, so I use componentWillMount to dispatch my getTransaction() action and the resulting success (i put redux-logger as middleware to know success or failure). The problem is my redux store is not getting an update. I need this data to passing to child component as props. The main problem is at Transaction.js This is my code

Transaction.js

import React from "react";
import { connect } from "react-redux"
import { withRouter } from 'react-router-dom';

import { getAuthenticatedUsername } from '../../utils/authorization'
import Layout from "./../layout/Index"
import Table from "../../components/table/Table"

import { getTransaction } from "../../actions/transactionActions"

import "./styles.scss"

function mapStateToProps(state){
  return {
    transaction: state.transaction
  }
}
class Transaction extends React.Component {

  componentWillMount() {
    this.props.dispatch(getTransaction());
  }

  render() {
    console.log(this.props);//transaction not get updated, only get initial state from transactionActions
    return (
      <Layout username={getAuthenticatedUsername()}>
          <Table data={this.props.transaction}/>
      </Layout>
    );
  }
}

export default connect(mapStateToProps)(Transaction);

client.js

import React from "react"
import ReactDOM from "react-dom"
import { Provider } from "react-redux"
import { 
  HashRouter,
  Link,
  Route,
  Redirect
} from 'react-router-dom'

import { isAuthenticated, setAuthorizationToken } from './utils/authorization'

import store from "./store/store"
import Login from "./pages/Login"
import Register from "./pages/Register"
import CatExpense from "./pages/isi/CatExpense"
import CatIncome from "./pages/isi/CatIncome"
import Transaction from "./pages/isi/Transaction"

import "../styles/styles.scss"

setAuthorizationToken(localStorage.jwtToken);

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    isAuthenticated() ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

ReactDOM.render(
  <Provider store={store}>
    <HashRouter>
      <switch>
        <Route exact path="/" component={Login}/>
        <Route path="/login" component={Login}/>
        <Route path="/register" component={Register}/>
        <PrivateRoute path="/transaction" component={Transaction}/>
        <PrivateRoute path="/catincome" component={CatIncome}/>
        <PrivateRoute path="/catexpense" component={CatExpense}/>
        <Redirect path="*" to="/"/>
      </switch>
    </HashRouter>
  </Provider>, document.getElementById('app'));

store.js

import { applyMiddleware, createStore } from "redux";
import axios from "axios";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";

import reducer from "../reducers/index";

const middleware = applyMiddleware(promise(), thunk, createLogger());
export default createStore(reducer, middleware);

transactionReducer.js

const initialState = {
  isFetching: false,
  isSuccess: false,
  transaction: {}
}
export default function reducer(state = initialState, action ) {
  switch (action.type) {
    case "GET_TRANSACTION_PENDING": {
      return { ...state, isFetching: true }
      break;
    }
    case "GET_TRANSACTION_REJECTED": {
      return { ...state, isFetching: false, error: action.payload }
      break;
    }
    case "GET_TRANSACTION_FULFILLED": {
      return { ...state, isSuccess: true, transaction: action.payload }
      break;
    }
  }
  return state;
}

transactionActions.js

import axios from "axios"
import jwt from "jsonwebtoken"
import { isAuthenticated } from '../utils/authorization'

export function getTransaction(){
  isAuthenticated();
  return function(dispatch) {
    axios.get("http://localhost:8000/listTransaction")
      .then((response) => {
        dispatch({type: "GET_TRANSACTION_FULFILLED", payload: response.data})
      })
      .catch((err) => {
        dispatch({type: "GET_TRANSACTION_REJECTED", payload: err})
      })
  }
}
BIlly Sutomo
  • 407
  • 1
  • 6
  • 20

2 Answers2

5

I have found the problem myself. Actually the data is get updated, only little late. Before the data get retrieved, the data already passed as props to the child component where the child component map that data which is null. That's what cause the problem. So i put validation if null render null, otherwise render data. After child component get the data, it will auto rerender to show the data.

BIlly Sutomo
  • 407
  • 1
  • 6
  • 20
0

Two things. First, you should dispatch the action in componentDidMountper the React docs. https://facebook.github.io/react/docs/react-component.html#componentdidmount

Second, you need to pass Redux's mapDispatchToProps() function to your connect, with the actual action passed in.

  const mapDispatchToProps = (dispatch) => {
   return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
   }
  }

export default connect(mapStateToProps, mapDispatchToProps)(TodoApp)

What is mapDispatchToProps?

https://github.com/reactjs/react-redux/blob/master/docs/api.md

  • You need to have a look at this answer and read the docs https://stackoverflow.com/questions/41670146/why-is-there-no-need-for-a-mapdispatchtoprops-function-here/41671030#41671030 – Shubham Khatri Jul 30 '17 at 18:00