0

I'm new to React and pretty confused I must say, thus the question. I build the first iteration of my app fetching data inside my root/container components. Here's the container

class HomePage extends React.Component{

  constructor(props) {
    super(props);
    this.state = {user: null};  

  }
  componentWillMount() {

    getUserData(xobni_api).then((result) =>{
      this.setState({user : result});

    });


  render(){
    return(

        {this.state.user &&
        <div className="col-md-8 middle-pane">
          <Viewer images={this.state.user} />
        </div>
        }

    );
  }

}

This is the getUserData function,

export function getUserData(url){

  return fetch(url, { credentials : 'include'})
              .then((response) => { return response.json();})
              .then((data) =>{ return new User(data.public_id, data.yahoo_profile.givenName, data.yahoo_profile.familyName, data.credentials[0].account);});
}

Now I'm in the process of restructuring my app and want to get the manage the data using Redux. Here's my condifgureStore

export default function configureStore(initialState){
  return createStore(
    rootReducer,
    initialState,
    applyMiddleware(reduxImmutableStateInvariant())
  );
}

And I'm instantiating the Store in my index.js

const store = configureStore(initialState);

And then I need to pass this state into my individual Reducers, like this one.

export default function homePageReducer(state, action){
  switch(action.type){
    case 'SEND_IMAGE':
      //send image

    default:
      return state;
  }
}

I can't seem to find the right way to do this. I would really appreciate if someone can help with a slightly detailed answer as to how I can move the api call out of my component, make the call in the store, set the initial State and then pass it back to the component. Thanks in advance.

2 Answers2

1

One of the redux concepts that I hammered into my head is:

Dispatch actions to update the store no matter what (fetching data, calling chrome APIs, etc.)

Let's try out that concept on your case:

fetch(url, { credentials : 'include'})
  .then((response) => { return response.json();})
  .then((data) => {
    // create a new user
    const newUser = new User(data.public_id, data.yahoo_profile.givenName, data.yahoo_profile.familyName, data.credentials[0].account);

    // once you have the new user.
    // time to update the store.
    dispatch({
      type: 'UPDATE_STORE_WITH_NEW_USER'
      payload: {
        user: newUser,
      },
    });
  });

The next question is, how do you get the dispatch function. One way is to import the instantiated store and call the dispatch function like this:

import store from 'path/to/store';

store.dispatch({ type: 'ACTION_TO_BE_DISPATCHED' });

That's bad. Now you have to import the store every single time you need to dispatch an action.

Introducing redux-thunk!! See here to understand why you need this. With redux-thunk, you can create actions like this:

fetchAndUpdateStore() {
  // notice that this returns a function
  return (dispatch) => {
    fetch(url, { credentials : 'include'})
      .then((response) => { return response.json();})
      .then((data) => {
        // create a new user
        const newUser = new User(data.public_id, data.yahoo_profile.givenName, data.yahoo_profile.familyName, data.credentials[0].account);

        // now you can dispatch function easily.
        dispatch({
          type: 'UPDATE_STORE_WITH_NEW_USER'
          payload: {
            user: newUser,
          },
        });
      });
  }
}

instead of plain basic actions like this:

someBasicAction = () => ({
  type: 'BASIC_ACTION',
});

Now, the last part is to dispatch the action and connect your component to your data in the store.

import { connect } from 'react-redux';
import fetchAndUpdateStore from 'path/to/that/action';

const mapStateToProps = (state) => ({
  user: state.user,
});

const mapDispatchToProps = (dispatch) => ({
  fetchThenUpdate: () => (
    dispatch(fetchAndUpdateStore())
  ),
});

connect(mapStateToProps, mapDispatchToProps)(YourComponent);

Finally in your component, you can call this.props.fetchThenUpdate.

Community
  • 1
  • 1
sammkj
  • 177
  • 2
  • 10
0

I would leave the API call in the component and dispatch an action when the call is finished. With this, you have no side effects in configureStore and can give the user feedback about the current progress (e.g. by showing a loading spinner)

inyono
  • 424
  • 2
  • 6