I have recently begun coding in Redux.
Before Redux with AngularJS it was easy to map models with state using $localstorage. I just can figure out the best way to do that with Redux.
Should I be dispatching and action and ask reducers to read local storage for in my code ?
Or should I allow local storage to be managed with a global object ?
There are few ways.
Just note that for syncing to localStorage you need to call JSON.stringify which is quite expensive, so please don't do that often and also with large data structures as it might hurt app's performance.
1) Sync whole Redux store to Local Storage. You can use existing solution for that eg. https://github.com/elgerlambert/redux-localstorage
I would not recommend to sync whole store as you might sync also state which should not be persisted after refresh and also you might make application slower; For better performance you can use paths argument in above library or use one of another options.
To see how you can build such functionality manually, there is great explanation video from Dan https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage
2) Manually build simple cache middleware like below, which might catch specific actions you would like to sync with local storage
const cacheMiddleware = store => next => action => {
if(action.type !== 'GET_SOMETHING') {
return next(action);
}
const data = getFromLocalstorage();
if(!data) {
// Fetch and put to localstorate for later use
const data = fetchFromServer();
return next({ type: 'SERVER_RESULT', data });
}
return next({ type: 'CACHED_RESULT', data });
};
3) If you are using Redux Thunk you can perform caching there as you are allowed to have side effects in actions.
You can find more info about Redux middleware here https://redux.js.org/advanced/middleware
Related
Last year I spent some time learning Vue 2. I really enjoyed the framework but did not move forward with a project. I now have time for a project but I'd like to use Vue 3 with the composition API. I'll be using Firebase as the backend. I've seen conflicting techniques on whether or not to use Vuex.
For example, I'd like to store a "currentUser" object in global state that can be accessed from any component in the app. Normally, it would be done using Vuex. I'd have a getter to return the object, an async action to get the data from firebase and a mutation to set the state.
However, I've seen several Vue 3 code examples that do not use Vuex at all, instead they do something like this to get/set a currentUser in an app wherever it is needed for example in a navbar component.
composables/getUser.js
import { ref } from 'vue'
import firebase from 'firebase/app'
// refs
const user = ref(firebase.auth().currentUser)
// auth changes
firebase.auth().onAuthStateChanged(_user => {
console.log('User state change. Current user is:', _user)
user.value = _user
});
const getUser = () => {
return { user }
}
export default getUser
With this little bit of code above, I'm able to import getUser.js and access the currently logged in user using code like this. Also, the user object is now reactive:
<script>
import getUser from '../composables/getUser'
export default {
setup() {
const { user } = getUser()
return { user }
}
}
</script>
It seems I can use these little functions to get data from db directly without the need to use the Vuex pattern, which I find to be a bit more complicated.
So, my question is - if I'm starting a new Vue 3 project, is it ok to create "composable" functions to get/set data and import them into my components instead of using Vuex? Are there any downsides to this method? Or should I just stick with Vuex?
Short answer - You don't need it.
Long answer - It depends.
It depends mostly on your app and how often do you use "currentUser" data inside your components. If it's in 2 or more components, how often do you want to perform actually fetching from backend?
Once on app-init/login or every time each component mounts?
(probably once)
Does it need to be reactive? If yes - then you'll probably use centralized data pattern, your own or a library. Taken that into consideration it's probably more simple to just use Vuex.
I'm new to all of these technologies, but as far as I understand it, you can use React Native with Redux and Firebase without react-redux-firebase. You could just use
react
react-native
redux
react-redux
react-native-firebase
Then you load data from Firebase (e.g. Firestore) and put the data in a reducer so it gets merged into the redux store.
Why do I need react-redux-firebase? What problem does it solve?
I have tried its docs, but they seem to be written for someone who is already familiar with its goals. They do not really explain, and when reading the examples, I do not understand why I specifically need react-redux-firebase instead of the setup listed above.
Firebase is on your state, listen to it an modify it, it will change your Firebase database. After the data on the database is changed the components listening will change as well.
This will create an item in the database
updateTodo: props => () => {
return firebase.update(`todos/${params.todoId}`, { done: !todo.isDone })
}
So any component listening to that node will get updated:
connect((state) => ({
todos: state.firebase.data.todos,
// profile: state.firebase.profile // load profile
}))
It solves the problem of having multiple sources of truth, your Firebase database is your only source of truth, otherwise, you change your local data and then you update the data online and then if it works nothing else but if it fails you have to update the local data again
I have stored a payload in the redux store. I couldn't access the store object. How to access the store object? I wanted to access it by redux-saga. I tried even by normal redux to access store but could'nt!
I wanted to access it by redux-saga. I tried even by normal redux to access store but could'nt!
In general case redux-saga combines two things - redux middleware and independent process manager. If you need only to fetch and directly manipulate with redux internal state without process managing, probably, it's better to write own simple middleware (https://redux.js.org/docs/advanced/Middleware.html ) and maybe compose it with saga.
Of course, you can easily use select effect (https://redux-saga.js.org/docs/api/#selectselector-args ). but take in account, that middleware first forwards the action to the reducers and then notifies the Sagas. This means that when you query the Store's State, you get the State after the action has been applied.
Most likely it's better to store mandatory information info current saga's closure, for example, before while-true loop in dedicated saga process.
function* someSaga() {
const localState = {};
while(true) {
const action = yield take('ACTION_PATTERN');
// some logic to dispatch the action
yield put('SOME_AFTER_ACTION')
}
}
I am confused by the docs. I am trying to use Redux-storage middleware and this is how they show the store is created with the middleware:
const middleware = storage.createMiddleware(engine);
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore);
const store = createStoreWithMiddleware(reducer);
But the Redux docs show this:
let store = createStore(
todos,
[ 'Use Redux' ], // How do I put here the data from the redux-storage?
applyMiddleware(middleware) // here goes the redux-storage
)
createStore requires an initial store value to be passed, but I can't load the stored values without having a store. This is a kind of catch 22. What did I miss here?
You actually miss nothing and that is intended behavior of redux-storage: there is a gap between creating redux store and the moment it got filled with the stored data. That is because storage engine provided to redux-storage createLoader can have an async nature in general case.
The common pattern to deal with that is following:
Your app starts up with uninitialized store state
It shows some kind of a preloader to your user
App creates loader and loads stored state: const load = storage.createLoader(engine); load(store);
Wait store to be rehydrated and hide preloader.
There is another store peristing lib out there: redux-persist. But initialization process works the same way, except you don't have to call load explicitly.
I'm using Redux to write a NodeJS app. I'm interested in allowing users to dynamically load middleware by specifying it at runtime.
How do I dynamically update the middleware of a running Redux application to add or remove middleware?
Middleware is not some separate extension, it's part of what your store is. Swapping it at runtime could lead to inconsistencies. How do you reason about your actions if you don't know what middleware they'll be run through? (Keep in mind that middlewares don't have to operate synchronously.)
You could try a naive implementation like the following:
const middlewares = [];
const middlewareMiddleware = store => next => act => {
const nextMiddleware = remaining => action => remaining.length
? remaining[0](store)(nextMiddleware(remaining.slice(1)))(action)
: next(action);
nextMiddleware(middlewares)(act);
};
// ... now add/remove middlewares to/from the array at runtime as you wish
but take note of the middleware contract, particularly the next argument. Each middleware receives a "pass to the next middleware" function as part of its construction. Even if you apply middlewares dynamically, you still need to tell them how to pass their result to the next middleware in line. Now you're faced with a loss-loss choice:
action will go through all of the middleware registered at the time it was dispatched (as shown above), even if it was removed or other middleware was added in the meantime, or
each time the action is passed on, it goes to the next currently registered middleware (implementation is a trivial excercise), so it's possible for an action to go through a combination of middlewares that were never registered together at a single point in time.
It might be a good idea to avoid these problems alltogether by sticking to static middleware.
Use redux-dynamic-middlewares
https://github.com/pofigizm/redux-dynamic-middlewares
Attempting to change middleware on-the-fly would violate the principle of 'pure' actions and reducer functions, because it introduces side-effects. The resulting app will be difficult to unit-test.
Off the top of my head, it might be possible to create multiple stores (one for each possible middleware configuration), and use a parent store to provide the state switch between them. You'd move the data between the sub-stores when switching. Caveat: I've not seen this done, and there might be good reasons for not doing it.