0
votes

I have been reading several documents and watching videos regarding React Redux, but since all of them are different I wasn't able to apply that knowledge to some real project.

I will try to enumarate the process in order to use React Redux together.

Directory Structuring

  • project
    • src
      • components
        • User
          • index.js (Container component)
          • page.js (Presentational component)
      • actions
        • users.js
        • index.js (exports actionCreators combination)
      • reducers
      • constants
        • actionTypes.js
      • services
        • users.js
      • index.js
      • store.js
      • public
      • index.html

Redux Setup

  1. We create constants in project/src/constants/actionTypes.js:
    export const CREATE_USER = 'CREATE_USER';
    export const DELETE_USER = 'DELETE_USER';
    export const UPDATE_USER = 'UPDATE_USER';
    
  2. We create actionCreators en project/src/actions/users.js y luego se combinan en project/src/actions/index.js:

    • users.js

    import { CREATE_USER } from '../constants/actionTypes';
    
    export default function createUser(user) {
        type: CREATE_USER,
        user
    }
    
    • index.js

    import { createUser } from './users';
    
    export default {
        createUser
    }
    
  3. We create reducers in project/src/reducers/users.js and they are combined in project/src/reducers/index.js using combineReducers():

    • users.js

    import { CREATE_USER, UPDATE_USER, DELETE_USER } from '../constants/actionTypes';
    import { createUser } from '../services/users';
    
    const initialState = {
        name: '',
        password: '',
        email: ''
    }
    
    export default function users(state = initialState, action) {
        switch (action.type) {
            case CREATE_USER:
                state = createUser(action.user);
                return state;
        }
    }
    
    • index.js

    import users from './users';
    
    export default combineReducers({
        users
    })
    
  4. We create store in project/src/store.js:

    import { createStore } from 'redux';
    import reducers from './reducers';
    
    export const store = createStore(reducers);
    

    React Redux Setup

  5. We wrap component application <Provider> in project/src/index.js:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Provider } from 'react-redux';
    import { store } from './store';
    
    const Root = () => (
        `
            <Provider store={store}>
                <App />
            </Provider>
        `
    )
    
    ReactDOM.render(Root, document.getElementById('root');
    
  6. We transform component state to properties with mapStateToProps in project/src/components/User/index.js:

    import React, { Component } from 'react';
    import { createUser } from '../../actions/users';
    import Page from './page';
    
    class User extends Component {
        render() {
            return <Page users={this.props.users} />
        }
    }
    
    const mapStateToProps = state => ({
        users: this.props.users
        // what is mapped here?
    });
    
    const mapDispatchToProops = dispatch => ({
        // what about here?
    });
    
    export default connect(mapStateToProps, mapDispatchToProps)(User);
    

So, the question would be, is this React-Redux cycle well formed? What is missing or wrong?

1
You're pretty much just asking: "is the structure of my project fine?" And the answer I guess is yes, it is fine, it should work. (Although, your mapStateToProps should probably be users: state.users in this case and your action should just return action.user.) However, I'm not sure what kind of answer you're looking for, SO is for solving specific issues, I think this is more suited for Code Review once you get your project going.Yannick K
I was pretty much asking for that: Is my folder structure ok?" and that too, "what should be there inside mapStatetToprops". Now I see, is it ok that the "fetch" or "service" functionality is inside the reducer? Well, I guess, thank you.Maramal
I added an answer that might be of help concerning the "fetching/service" functionality you're talking about and where to put it.Yannick K
@YannickK, I agree, this should be migrated over to Code Review Stack Exchange.Daniel

1 Answers

1
votes

Yes, the folder structure works well. As for the "fetch" or "service" functionality you're talking about, I'll give you an example of what actions and reducers both should, in a basic example, do.

So if you're working with a backend which you're "fetching" anything from, I'd recommend adding that functionality in the action, not the reducer:

import { USERS_FETCHED } from '../constants/actionTypes';
import { baseUrl } from "../constants/baseUrl";

const usersFetched = users => ( { // action to dispatch
  type: USERS_FETCHED,
  users,
} );

export const fetchUsers = () => ( dispatch ) => { // export for mapDispatchToProps
  request( `${ baseUrl }/users` )
    .then( response => {
      dispatch( usersFetched( response.body ) ); // dispatch the action to reducer
    } )
    .catch( console.error );
}; // in your case you import createUser(), but it works either way

Now the action is concerned with functionality, in contrast the reducer is only concerned with managing the Redux state:

import { USERS_FETCHED } from "../constants/actionTypes";

export default ( state = null, action = {} ) => {
  switch ( action.type ) {
    case USERS_FETCHED:
      return action.users;

    default:
      return state;
  }
};

Functionality in the reducer is fine, but it should only be concerned with managing state. You can imagine how cluttered the code could get if you start fetching any data here, not to mention problems with asynchronicity. Of course, this is just one way to do it, but it works solidly. Hope this helps you in some way.