Am I getting the state value correctly in Redux? - redux

I'm getting the value of a component through redux store's getState(). Here's what it looks like
handleFormSubmit (event) {
event.preventDefault();
// have to get this.context because my prop value doesn't update with a change in child component
const value = this.context.store.getState();
if (value._root.entries[3][1]._root.entries[1][1]){
browserHistory.push('/place/' + value._root.entries[3][1]._root.entries[1][1]);
}
To get redux values, do we really need to have this complex code?
value._root.entries[3][1]._root.entries[1][1]
Edit Thanks to Abdul for mentioning the connect libraries. I'll add the code here
constructor(props, context) {
super(props, context)
Here's connect...
export default connect(mapStateToProps, mapDispatchToProps)(SimpleForm);

Figured it out!
Use the .get on the store from getState
const value = this.context.store.getState();
const home = value.get('home');
const getPlace = home.get('place_id');

Related

Vue3 - OnMount doesn´t load array

In Vue 3 i need to fill some array with result of store. I import store like this
Imports
import { onMounted, ref, watch } from "vue";
import { useTableStore } from "../stores/table";
Then i declare values and try to fill it
const search = ref(null);
const searchInput = ref("");
const edition = ref([]);
const compilation = ref([]);
const debug = ref([]);
const navigation = ref([]);
const refactoring = ref([]);
const store = useTableStore();
onMounted(() => {
store.fetchTable();
edition.value = store.getEdition;
compilation.value = store.getCompilation;
debug.value = store.getDebug;
navigation.value = store.getNavigation;
refactoring.value = store.getRefactoring;
});
Values doesn´t fill it. Is strange, if use watcher like this
edition.value = store.getEdition.filter((edition: String) => {
for (let key in edition) {
if (
edition[key].toLowerCase().includes(searchInput.value.toLowerCase())
) {
return true;
}
}
});
Array get values.
So, the problem is: How can i get store values when view loads?
Maybe the problem is the store returns Proxy object...
UPDATE 1
I created a gist with full code
https://gist.github.com/ElHombreSinNombre/4796da5bcdcf6bf4f36f009132dd9f48
UPDATE 2
Pinia loads array data, but 'setup' can´t get it
UPDATE 3: SOLUTION
Finally i resolved the problems and upload to my Github. I used computed to get data updated. Maybe other solution was better.
https://github.com/ElHombreSinNombre/vue-shortcuts
Your onMounted lambda needs to be async, and you need to wait the fetchTable function. Edit: Try using reactive instead of ref for your arrays. Rule of thumb is ref for primitive values and reactive for objects and arrays.
const search = ref(null);
const searchInput = ref("");
const edition = reactive([]);
const compilation = reactive([]);
const debug = reactive([]);
const navigation = reactive([]);
const refactoring = reactive([]);
const store = useTableStore();
onMounted(async () => {
await store.fetchTable();
edition.push(...store.getEdition);
compilation.push(...store.getCompilation);
debug.push(...store.getDebug);
navigation.push(...store.getNavigation);
refactoring.push(...store.getRefactoring);
});
If what you need is the component to not be rendered until data is ready, you'll need a flag in your data that works along with a v-if to render the component when everything is ready, something like this:
// in your template
<div v-if="dataReady">
// your html code
</div>
// inside your script
const dataReady = ref(false)
onMounted(async () => {
await store.fetchTable();
dataReady.value = true;
});

Setting initial state using recoil in a nextjs app with ISR and SWR

I'm trying to figure out how to set my initial recoil state while still using nextjs`s ISR feature.
So I made a product.ts file inside of a states directory the file contains the following code
const productsState = atom({
key: 'productState',
default: []
})
I thought about calling my api here and instead of setting the default as an empty array have it filled with data from the api call, but I'm sure I would lose out of ISR and SWR benefits that nextjs brings?
So I thought about setting initial state inside of the getStaticProps method
export const getStaticProps: GetStaticProps = async () => {
const res: Response = await fetch("http://127.0.0.1:8000/api/products");
const {data} = await res.json();
return {
props: {
data
},
revalidate: 10
}
}
But this would only run once on build time so data would be stale, so I made a hook to get my products using SWR
import useSWR from "swr";
import { baseUrl} from '../lib/fetcher'
export const useGetProducts = (path: boolean | string, options: {} = {}) => {
if (!path) {
throw new Error("Path is required")
}
const url = baseUrl + path
const {data: products, error} = useSWR(url, options)
return {products, error}
}
this is then called inside of the page component
const Home: NextPage = ({data}: InferGetStaticPropsType<typeof getStaticProps>) => {
const {products, error} = useGetProducts('/api/products', {
initialData: data,
})
}
Now I'm just wondering if this is a viable way to set initial state in recoil without sacrificing ISR and SWR benefits?
coming from vue/nuxt I would make a global store where I would call my api and set state to the api data, but it seems in react/recoil it's a bit different?

Dispatch actions with Redux Toolkit requires two arguments

Using Redux Toolkit, I'm trying to dispatch an action without context of event or etc., so I get the following error:
error TS2554: Expected 2 arguments, but got 1. An argument for 'action' was not provided.
With following code:
const App = () => {
const dispatch = useDispatch();
useEffect(() => {
(async () => {
const result = await fetchConfig();
dispatch(setConfig({ ConfigReducerState: result })); // ---> Error is here <---
})();
}, [dispatch]);
};
The reducer:
export const configSlice = createSlice({
name: 'config',
initialState,
reducers: {
setConfig(state, action) {
const { server, map } = action.payload;
state.server = server;
state.map = map;
},
},
});
Usually I give one parameter to action creator functions - object representing the payload, no need to refer the state. But here I can't. What am I doing wrong?
I've seen this before and every time, it was... a bug in IntelliJ/WebStorm.
See https://youtrack.jetbrains.com/issue/WEB-46527 and https://youtrack.jetbrains.com/issue/WEB-42559 - essentially, WebStorm has their own "quick TypeScript interpolation that does not use the official tsserver for type checking, but something self-cooked, that guesses types just based on things having similar names - and regularly gets things wrong.
If I understand their system correctly, you should be able to see the correct types by hovering over while holding Ctrl down.
In the end, I can't really tell you how to fix this other than switching to an IDE that does not randomly guess, but actually uses TypeScript to evaluate TypeScript types.
How did you import setConfig? I had the same issue and it turned out that by mistake I used
import setConfig from './configSlice'
instead of
import { setConfig } from './configSlice'
It was importing the default export (whole slice reducer, aliased as setConfig) instead of just this one function...

Redux: dispatch function to store?

How is it possible to save a function as state in redux store?
Example:
I pass a function as parameter to a redux-thunk dispatcher function and i want to save this filter function in my redux store:
export const SET_FILTERED_USERS = 'SET_FILTERED_USERS';
export function setFilteredUsers(filter) {
return (dispatch, getState) => {
const allUsers = getState().users.allUsers;
const filteredUsers = allUsers.filter(filter);
dispatch({
type: SET_FILTERED_USERS,
data: {
filteredUsers,
filter
}
});
const activeUser = getState().users.activeUser;
if (activeUser && !_.isEmpty(filteredUsers) && filteredUsers.indexOf(activeUser._id) === -1) {
dispatch(setActiveUser(filteredUsers[0]));
} else {
dispatch(setActiveUser(allUsers[0]));
}
}
}
In ReduxDevTools i can see, "filter" is not dispatched and saved in store. Is there a way to do this?
Thanks
Update: my shortend reducer:
import {
SET_FILTERED_USERS
} from '../actions/users';
import assign from 'object-assign';
export const initialState = {
filter: null,
filteredUsers: null
};
export default function (state = initialState, action = {}) {
const {data, type} = action;
switch (type) {
case SET_FILTERED_USERS:
return assign({}, state, {
filteredUsers: data.filteredUsers,
filter: data.filter
});
default:
return state;
}
}
As Sebastian Daniel said, don't do that. Per the Redux FAQ, that breaks things like time-travel debugging, and is not how Redux is intended to be used: Can I put functions, promises, or other non-serializable items in my store state?
What you could consider as an alternative is storing some kind of description of the filtering you want. As a sort of relevant example, in my current prototype, I'm creating a lookup table of dialog classes that I might want to show, and when I need to show one, I dispatch an action containing the name of the dialog type. My dialog manager class pulls that "dialogType" field out of state, uses that to look up the correct dialog component class, and renders it.
The other question, really, is why you actually want to store a function in your state in the first place. I see what you're trying to do there, but not actually what you're hoping to accomplish with it.

Simplest Redux-React app in ES5: why aren't props being passed down?

I'm trying to build the most trivial possible Redux app. I have an initial state, I make a Redux store, I pass the store to ReactRedux.Provider, and I have my app as a child of the Provider.
However, my APP view, written as a stateless functional component, is not receiving any props. (The same is true if I write my APP view using React.createClass and checking for this.props in the render method.)
What am I doing wrong?
var initialState = {
counter: 0
};
var rootReducer = function(state, action) {
if (!state) state = initialState;
switch (action.type) {
default: // don't do anything yet
return state;
}
};
var store = Redux.createStore(rootReducer, initialState);
var APP = function(props) {
return React.createElement(
'div',
{},
props.counter // props is not defined
);
};
ReactDOM.render(
React.createElement(
ReactRedux.Provider,
{store: store},
React.createElement(APP, null)
),
document.getElementById('app')
);
You need to use the connect() function provided by React-Redux to create a wrapped version of your "APP" component that is actually hooked up to the store. See http://redux.js.org/docs/basics/UsageWithReact.html .
You can write the equivalent logic yourself for subscribing to the store and passing updated props to a component, but generally there's not a good reason to do so.
For future reference, I am going to add here an example of a working case in codepen not using babel neither the integrated version of jsx.
https://codepen.io/kanekotic/pen/LxbJNJ
Solution ;TL;DR
As commented before there is missing the redux connect
var mapstateToProps = function(state) {
return{
counter: state.counter
}
}
function mapDispatchToProps(dispatch){
return Redux.bindActionCreators(ActionCreators, dispatch);
}
var connectedApp = ReactRedux.connect(mapstateToProps,mapDispatchToProps)(APP)
and use then in the component connectedApp and no APP

Resources