How to properly access Redux store in the React component? - reactjs

I'm working on React frontend, currently have working backend. I would like to display server-side messages during login, besides client-side validation, like if all fields are filled. I'm having troubles with accessing Redux store in my component, even though I've wrote mapStateToProps function and as I've read, values returned from an action should be mapped to props, so I should be able to retrieve them. My code: https://codesandbox.io/s/rough-firefly-4kcdl (I'm sorry for syntax error regarding an arrow function). As you can see on the attached screenshot, there are some values in Redux store, and I would like to be able to use some of them in coresponding component.

In your auth reducer case LOGIN_FAILURE your new state has a different structure, instead of returning { action } return { ...state, errors: action.errors, isLoading: action.isLoading } because that's what your component is expecting

Hey i have share a link with you where i have defined how you can use mapStateToProps and mapDispatchToProps in mostly used pattern
https://codesandbox.io/s/cool-oskar-oj4s4?fontsize=14
in your reducers please change your Login_Failure case return statement.
you have to return all the remaining state to component
because reducer always return state object
return {
...state
}
and check you Login component i have defined proper way to get updated state and dispatch your actions
you can get your state with your reducers name

Related

How to pass Redux Reducer pointer to React Context?

So in short I am trying to pass a reducer to a context file and have it so that if the state of reducer is updated then I can view that new state in the context file.
Here is my reducer:
function StillUploadReducer(state = true, action){
switch (action.type){
case 'stillUpload':
return action.payloadData
default:
return state
}
}
Heres how im passing it to a firebase context file:
const addData = await firebase.addExercise(
Data,
props.StillUploadReducer
);
In the context file i do a console.log of the value and i get the original value passed in. The main issue with this is I want the ability for the user to change the state of the reducer while I await on a video being uploaded so that if the state has changed then it is reflected in the context file.
The user changes the reducer using the action:
const StillUpload = (dataToPass) => {
return{
type: 'stillUpload',
payloadData: dataToPass,
}
}
I have console logged the value of the reducer outside the context file and i can see it is being updated I just dont know how to see that change reflected in the context file. Does anyone have any ideas? Thx ahead of time.
A reducer is just a pure function. It has no state, so passing the reducer as an argument to another function cannot achieve what you want.
I'm not sure what you mean by "context file" or what firebase.addExercise does, but you should most likely instead use the useSelector hook which is exactly designed for a component to rerender every time the corresponding part of the state changes.
You should also not use mapStateToProps anymore which is a legacy API for the legacy class components.

Using Redux, can any component get and set (by action) any data in the store?

Using Redux, is it true that any component and sub-component on the page get all data of the one and only store, and be able to send out any action at all, even if it is not meant for that component to send out?
Can all the components use
const store = createStore(mainReducer);
let state = store.getState();
and be able to see all states of the whole app? Can any component dispatch any action all all? So for example, if there is Counter component and a Comment component, can the Comment component accidentally send out a "INCREASE_COUNT" action?
Using Redux any component "can" access any data in the store, but for the access you have to 'connect' it with the store. When you 'connect' you also specify a map to which part you want this component to access. That's how you are in control, it only gets access to what you want only.
The same goes for actions. You have to map the actions also - which component can dispatch which action, when your 'connect' to the store.
Check this out for more info - https://redux.js.org/basics/usage-with-react
To most part of your question, it seems the answer is Yes.
Yes, the components can access the whole store ( one it has subscribed to ) and can dispatch actions when needed. I do not think there is any way you can put action/store behind some restrictions.
can the Comment component accidentally send out an "INCREASE_COUNT" action? Yes if you try to dispatch it again from the child component.
If you could add any specific example you have to ask, I can add more to my answer.
I hope it helps you !
" every component has access to the store" is wrong, it is like this " every component has access to the state and actions in the store that you "the developer" specify.
for a component to able to access the store, you need to wrap it in the connection function like so
import { connect } from "react-redux";
// Your component
export default connect(mapStateToProps, dispatchActionToProps);
// the component will only have access to the store props and actions that you specify
// in mapStateToProps and dispatchActionToProps
const mapStateToProps = state => {
return {
// state is the result of combineReducers
// whatevery key the component needs you can specify here
};
}
const dispatchActionToProps = dispatch => {
return {
// your store actions
};
}

Update Component after user logged in (React / Redux)

Yesterday I implemented an authentication system inside my react app. Additional I added Redux.
So now I have following reducers:
appReducer
listReducer
My store looks something like this:
{
appReducer: {
user: {
guid: null
}
}
listReducer: {
list: []
}
}
Component Structure:
- App (logic for authentication)
-- Navigation
-- Routes
--- ListPage (logic for list)
I want that the list[] rendered inside my ListPage component gets refreshed when a user logs in (when guid changes in store).
The current solution is, that i do a fetchList inside my AppActions, but I'm sure, that thats not a nice way to get what I want.
How do I correctly trigger my fetchList action, when guid's value changes?
Thanks!
Edit: fetchList is a redux action, which includes an axios api call
As you are using Redux you are updating the value of guid by dispatching an action to the reducer. I would say you should dispatch a list update action right after you updated the guid. As the list values get mapped as props in the component, it will get re-rendered.
I would make fetchList call inside componentDidMount function on your ListPage but also making an if statement, somethin like this:
componentDidMount(){
if(this.props.store.guid !== "null"){
this.props.fetchList();
}
}
I hope you get the point.
BTW in your store I don't know if you made it on purpose but I'd use null without quotation marks.

How reducers update the store

I am new to Redux and i am finding some problems with understanding concept of reducers,
I can see many examples showing it takes current state and return updated state,
My question is how it updates the Store by returning the new state ( i am finding difficult to understand the mechanism ),
can some one please explain me .
The Redux store is nothing but just an object holding all states of the application. The reducer is the only way to update the store.
The reducer is a pure function with takes an old state and returns a new state. In reducer what we need to do is that we just provide the old state which is store currently having and then the new state which we are going to change state. You can refer this for detailed explanation for reduce function.
In simple words, reducer takes existing state object updates some property passed through reducer function and returns new object state.
Following link has better explanation. This is very nice blog how to create your own redux. You will get exactly what happens in the redux store.
https://www.jamasoftware.com/blog/lets-write-redux/
this is image that i found very helpfull when i was learning the same concept.
Dispatch
When you dispatch any function it goes to all reducers and if the type of dispatch matches it will change the state of that reducer.
functionName:()=>(dispatch)({type:'some-thing-to-match',payload})
Reducers
That handle state change.
Store
Combination of all the reducers (root reducer).
const store = combineReducers({
Reducer1:r1,
Reducer2:r2,
Reducer3:r3
})
For example take the dispatch function in TodoList that matches in r1 and changes its state.Then by connect from 'react-redux' we will connect that reducers state to TodoList.
var mapStateToProps = state=>{
return:{
r1:r1
}
}
then react will react to any change in state. If state of r1 is changed then it will update that component.
Your question how it update store by returning state. Your reducer will get store(state) and function as input and change the store according to function and return the state to store.
Then we can connect our component to that store to catch any change in it.
As we can see in image. Dispatch will change the store's state.Then
you can import(connect) that reducer to see the changes in your
component.(here TodoItem is that component)
Actually this is the part that i was missing about reducers,The part i didnt catch was reducers out put has to be assigned to store property
let Action={type:'SET_VISIBILITY_FILTER',text: 'test pay load'}
//Invoking Reducer
let store=todoApp({},Action)
//Reducer
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
message: action.text
})
default:
return state
}
}

Reusable react-redux container components

In my React/Redux app I am often facing with the problem of implementing components with state which should be used throughout the app.
Let's take simple popup component as an example with open/close state which can be reused in any page.
Here is two possible approaches I found:
Use setState and "local" reducer (I use recompose.withReducer which is just syntax sugar for React's native setState) to manage its state. It looks easy and reusable until you need change the component's state in the other part of your page (close popup in out case). And you cannot just call some redux action to change the state.
Keep the component's state in the Redux store. With such approach we can call closePopupAction({ id }) in any place of the components tree to change it's state.` But we need somehow put its reducer (which i want to keep in the popup's folder) to the root reducer when the component is mounted and delete it when the component is unmounted. Plus we can have multiples popups in the page and each of them have its own state.
Did anybody face with a similar problem ?
I think you should keep state of component in redux. You can create reducer for this component and use combineReducers function in this way:
rootReducer = combineReducers({
moduleA: combineReducers({
popupA: popupReducer("id1"),
popupB: popupReducer("id2")
}),
moduleB: combineReducers({
popupA: popupReducer("id3")
})
})
});
then when you call closePopupAction("id1") reducer can check id and change proper part of state.
PS: Id should be provided in better way :)
You could mount each component's state to its own slice of the store.
So your closePopupAction actions would be called with that mount path:
closePopupAction({ mountPath: 'popups.popup1' })
and you would need only one reducer to handle all closePopupAction actions, which could be registered once at startup:
(state, { type, mountPath }) => {
if (type === 'CLOSE_POPUP_ACTION') {
// manipulate with the slice at `mountPath`, e.g.
return _.set(_.cloneDeep(state), `${mountPath}.isOpen`, false)
}
// ...
}

Resources