Fighting "what's going on" in react / contraction / saga / selector setup

Recently using ARc (Atomic React) for a project (this is great and I think has a ton of future validation of what will ultimately be an enterprise level product) BUT this is only future proof, t guessing it together is wrong and I am into currently cannot figure out how / when / where / why to use a selector in my application.

Read this: How is state passed to selectors in a react-redux app? which is great, but I think I need to see some more examples to actually get it.

The current problem I'm trying to solve is to get an object user

(which is app-wide) and also with that data create an easy-to-view slice of state for the account settings page where the user can change their name, email, etc. etc. I wouldn't want to just use the store user

because I don't want them to change anything until they actually hit submit, but want to keep the state of the form reduxed.

I upload to my user which is good (can be accessed via props in different containers where I want): Actions:

export const USER_GET_REQUEST = 'USER_GET_REQUEST'
export const USER_GET_REQUEST_SUCCESS = 'USER_GET_REQUEST_SUCCESS'
export const USER_GET_REQUEST_FAILURE = 'USER_GET_REQUEST_FAILURE'

export const getUserRequest = (params, resolve, reject) => ({
  type: USER_GET_REQUEST,
  params,
  resolve,
  reject,
})

export const getUserRequestSuccess = user => ({
  type: USER_GET_REQUEST_SUCCESS,
  user,
})

export const getUserRequestFailure = error => ({
  type: USER_GET_REQUEST_FAILURE,
  error,
})

      

Saga:

import { take, put, call, fork } from 'redux-saga/effects'
import api from 'services/api'
import * as actions from './actions'

export function* readGetUser() {
  try {
    const data = yield call(api.get, '/user')
    yield put(actions.getUserRequestSuccess(data))
  } catch (e) {
    yield put(actions.getUserRequestFailure(e))
  }
}

export function* watchUserGetRequest() {
  while (true) {
    const { params } = yield take(actions.USER_GET_REQUEST)
    yield call(readGetUser, params)
  }
}

export default function* () {
  yield fork(watchUserGetRequest)
}

      

Dilution:

import { initialState } from './selectors'
import { USER_LOGIN_SUCCESS, USER_GET_REQUEST_SUCCESS } from './actions'

export default (state = initialState, action) => {
  switch (action.type) {
    case USER_LOGIN_SUCCESS:
      return state
    case USER_GET_REQUEST_SUCCESS:
      return {
        ...state,
        user: action.user,
      }
    default:
      return state
  }
}

      

Selector (my obscene code is commented out, one line works before user

there is actually user data, BUT WHERE RUNNING DATA GO / HOW GETS IT.

export const initialState = {
  user: {},
}

export const getUser = (state = initialState) => state.user || initialState.user

// export const getUser = (state = initialState) => {
//   if (state.user) {
//     return Object.assign({}, state, {
//       formData: {
//         firstName: state.user.firstName,
//         lastName: state.user.lastName,
//         email: state.user.email,
//         phone: state.user.phone,
//       },
//     })
//   }
//
//   return initialState.user
// }

      

Code help is awesome, clear explanations get my unwavering affection and gratitude + mention in my autobiography.

+3


source to share


1 answer


Selector functions can and should be used wherever you want to extract specific pieces of data from the store. Think of them as "queries in your state tree", like a SQL query against a database.

They are most commonly used in your functions mapStateToProps

to retrieve the data needed for components, but also in places where you need to run conditional logic based on store content (like thunk action creators or sagas). You can even use them in gearboxes if you like.

Selectors are usually created using a library reselect

that remembers input. This means that the final function "output" will only work if the inputs do change. A simple example would be:

import {createSelector} from "reselect";

const selectUser = state => state.user;

const selectUserFirstName = createSelector(
    selectUser,
    user => user.firstName
);

const selectUserLastName = createSelector(
    selectUser,
    user => user.lastName
);

const selectUserFullName = createSelector(
    [selectUserFirstName, selectUserLastName],
    (firstName, lastName) => firstName + " " + lastName
);

      



In this example, the selector "firstName + lastName" will only work if one of the two inputs has actually changed. Otherwise, it will return the previous value of the cached result. This can be used like:

const mapState = (state) => {
    const userFullName = selectUserFullName(state);

    return {userFullName};
}

      

For more information on selectors, see the section under Redox Techniques # Selectors and Normalization in my React / Redux Reference List . I also use selectors in my Redux Practice Series . (As a related note, you might want to read Practical Redux Part 8: Drawing Format Control, or some of the articles on React and Forms in my reference list.)

+3


source







All Articles