Gergő Horváth
Gergő Horváth

Reputation: 3705

Fetch again, or set state? - react, redux

This is the question which always confuse me, so i decided that i'm asking you. What i mean is that i have a Node server, and an SQL database in the backend, and a redux store on the frontend. The main component fetches every time it did mount, processes the response, and dispatch it to the store. All what the user see depending on the store. So if a change happens, it gets uploaded to the database through the server, but if this change happens on the main component's child component, the state isn't gets uploaded to the store because the main component isn't do mount. Let me show what i mean:

//main component

componentDidMount(){
  fetch('http://localhost:3001/')
      .then(res => res.json())
      .then(items => {
        //items: [1, 2, 3]
        this.props.dispatch({
          type: 'GET_ITEMS',
          items
        });
      })
      .catch(err => console.log(err)))
}

//reducer

const initialState = {
  items: []
}
const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'GET_ITEMS' :
      return{
        ...state,
        items: action.items
      }
    default:
      return state
  }
};

//child component

userAddsNewElement = e => {
    fetch('http://localhost:3001/addElement', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        newElement: e.target.value //4
      })
    })
    //here, we have a few options:
    //we can send the whole `items` array as response from the server
      //and dispatch it as in componentDidMount
    //we can push the new element to the current state
    .catch(err => console.log(err)))
}

The above code just an illustration what i mean. Obviously the second solution looks better, but in my code's state i need to loop through 3 arrays to find the target element. But the amount of items are unknown both in the database, and both in the state. If i get the items from the database it gets processed with 2 maps, and then a sort. If i want to search the target item, as i mentioned, i need to do 3 nested loops to find the target element.

I know there's no "golden answer" to this question, but i want to know when to use which. Are there big differences between these methods (in performance)?

Upvotes: 0

Views: 997

Answers (1)

Matt Pengelly
Matt Pengelly

Reputation: 1596

what you're probably going to want to do is something like this:

Your backend state and your frontend state should be kept consistent, but you shouldn't NEED to request from the backend to have the state be the same. just make the changes to your store as needed after the backend requests go through. Your GET_ALL should only need to run once on component mount which will then set your stores initial state. After that you'll be modifying the store directly and the backend directly as well.

componentDidMount(){
  fetch('http://localhost:3001/')
      .then(res => res.json())
      .then(items => {
        //items: [1, 2, 3]
        this.props.dispatch({
          type: 'SET_ITEMS', // you'll need to set your reducer up for this
          items
        });
      })
      .catch(err => console.log(err)))
}

//child component

userAddsNewElement = e => {
    fetch('http://localhost:3001/addElement', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        newElement: e.target.value //4
      })
    })
    //here, we have a few options:
    //we can send the whole `items` array as response from the server
      //and dispatch it as in componentDidMount
    //we can push the new element to the current state ** this one **
    .then(() => { // if were here that means our post request didnt throw an error
      this.props.dispatch({
        type: 'ADD_ITEM',
        payload: e.target.value
      });
     })
    .catch(err => console.log(err)))
}

and then in your reducer:

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'GET_ITEMS' : // not using this anymore but you may for things later.
        return state.items
    case 'ADD_ITEM' :
      return {
       ...state,
       state.items.concat(action.payload)
      }
    case 'SET_ITEMS' :
      return{
        ...state,
        items: action.items
      }
    default:
      return state
  }
};

Upvotes: 1

Related Questions