I'm new to react navtive and wondering how to handle the route names for the react-navigation v5.
I'm starting of a company internal boilerplate project with react-navigation in version 4 and updating that to version 5. So far everything runs fine.
The problem now is, the project was using a file which had all the route names defined as so:
export const HOME_ROUTE = 'Home';
export const LOGIN_ROUTE = 'Login';
export const REGISTER_ROUTE = 'Register';
That also works in react-navigation v5.
Then I wanted to eliminate the warnings on the any type of the navigation prop. The documentation states I should add the type definition. Then I ran into the first problem.
With the route constants I would have liked to do it somehow like this:
export type RootStackParamList = {
HOME_ROUTE: undefined;
LOGIN_ROUTE: undefined;
REGISTER_ROUTE: undefined;
};
That does not work, as I cannot find a way to use constants in a type definition(Which makes sense).
I was thinking about removing the routeConstants altogether, but the disadvantage is that I do not have autcompletion on typing the route names, which might lead to hard to spot bugs. At least I think that might happen.
Is there a preferred way to handle this problem? I looked into a few other boilerplate projects but they all just used strings as the route names.
Thanks to a coworker I found the solution:
The syntax to unpack a constant is like this:
export type RootStackParamList = {
[HOME_ROUTE]: undefined;
[LOGIN_ROUTE]: undefined;
[REGISTER_ROUTE]: undefined;
};
Related
I am creating a new Vue 3 project and i saw many people online declaring refs like this.
const myVariable = ref(false)
Why are we using const all of a sudden in Vue 3? I get that refs wrap them in some way to make them editable but i still don't get why not declaring them like this:
let myVariable = ref(false)
I know it may sound a foolish question for Vue 3 devs but i cannot understand the reason behind changing values to constants.
During the meanwhile i am using the const declaration in composition API but i'd like to acknowledgwe the reason behind
it's preferences but the argument why const is used is when the value is not changing e.g:
const name = 'John';
// Shouldn't work.
name = 'Bill';
With ref(), you don't replace the variable but the property
const name = ref('John');
name.current = 'Bill';
Here's how eslint explains it:
If a variable is never reassigned, using the const declaration is better.
const declaration tells readers, โthis variable is never reassigned,โ reducing cognitive load and improving maintainability.
Docs (at the time of writing): https://eslint.org/docs/latest/rules/prefer-const
I"m porting my new app from vue2 to vue3. Since mixins are not recommended way of reusing code in vue3, Im trying to convert them into composable.
I've 2 mixins (methods) __(key) and __n(key, number) in mixins/translate.js which will translate any word into the app's locale.
module.exports = {
methods: {
/**
* Translate the given key.
*/
__(key, replace = {}) {
// logic
return translation
}
Now this is how I converted it as
Composables/translate.js
export function __(key, replace = {}) {
// logic
return translation
}
and since I need these functions to be accessbile in every component without explicitly importing. I'm importing it in app.js
import {__, __n} from '#/Composables/translate.js';
Questions
__() is not accessible in every component. How to make this function accessible in every component without explicit import
Is this the right of doing things?
These functions are required essentially in every component, declaring them in every component is impractical.
#1, You can put it into the globalProperties object
import {__, __n} from '#/Composables/translate.js';
const app = createApp(AppComponent);
app.config.globalProperties.__ = __;
app.config.globalProperties.__n = __n;
#2, though opinion based, importing for every component that needs it would be my preferred way.
I was wondering if it was possible with the new Vue composition API to store all the ref() in one big object and use that instead of a vuex store. It would certainly take away the need for mutations, actions, ... and probably be faster too.
So in short, is it possible to have one place for storing reactive properties that will share the same state between different components?
I know it's possible to have reusable code or functions that can be shared between different components. But they always instantiate a new object I believe. It would be great if they would depend on one single source of truth for a specific object. Maybe I'm mixing things up...
You can use reactive instead of ref.
For eg.
You can use
export const rctStore = reactive({
loading: false,
list: [],
messages: []
})
Instead of
export const loading = ref(false)
export const list = ref([])
export const messages = ref([])
Cheers!
I'm building a fairly large app using Vue and I have a lot of routes, names and logic behind them. I found a great question/answer about Vue Router here and it gave me a lot of ideas, but I wasn't able to find an answer for myself. If I missed something, please feel free to point me in the right direction.
Here are my issues:
Renaming hell: whenever I change a name of the route I have to go and find all the self.$router.replace({ name: 'OldRouteName' }) and change them. Maybe it doesn't sound like a big deal, but it is, especially in a big project
Global guard hell: in a way it is related to the #1 where I'm relying on the text literals to analyze from and to and call my next({ name: 'RouteName', replace: true })
There are a few other minor things on the list, but those two are big for me.
My thought was to create a global object and store route names there something like Vue.prototype.$myRoutes = {Index:'Index', Home: 'Home'} etc, but for some reason it doesn't feel right. I hope there is something better out there ๐
Any help appreciated, thanks!
Just like you can store Vuex mutation types in constants, so too can you store route names.
For example
// router/route-names.js
export const INDEX = "Index"
export const HOME = "Home"
Now wherever you need them, you just import from this file
import { INDEX, HOME } from '#/router/route-names'
Making changes means only editing one file.
For point #2, you can store extra data in each route's meta property. For example
{
name: ROUTE_A,
path: '/route/a',
meta: {
nextRoute: { name: ROUTE_B, replace: true }
}
}
Then you can use
next(from.meta.nextRoute)
I sometimes have need to send static props to a component, but the data actually comes from my Redux store. I.e. I need a access to state to fetch the data.
With static, I mean that this data won't change during the life of the component, so I don't want to select it from the store on each render.
This is how I solved it at first (the mapStateToProps part):
(state, ownProps) => ({
journalItemType: selectJournalItemType(state, ownProps.journalItemTypeId)
})
The component gets a JournalItemTypeId and the mapStateToProps looks it up in the store and sends the journalItemType to the component. JournalItemType is static metadata and won't change very often, and certainly not during the life of the component.
static propTypes = {
journalItemType: ImmutablePropTypes.map.isRequired,
}
The problem with this is that I call the selector at each render. Not a big performance hit, but feels wrong anyway.
So, I changed to this:
(state, ownProps) => ({
getJournalItemType: () => selectJournalItemType(state, ownProps.journalItemTypeId)
})
The first thing I do in the components constructor is to call getJournalItemType and store the result in the local state. This way the selector is only called once.
static propTypes = {
getJournalItemType: PropTypes.func.isRequired,
}
constructor(props) {
super(props);
this.state = {
journalItemType: props.getJournalItemType()
}
}
Question:
Is this the right way to do this?
Another way would be to let the component know about state so the component could call the selector itself. But I think it's cleaner to keep the state out of the component.
I could also call the selector and fetch the static data earlier in the call chain, but I don't have state naturally available there either.
Clarification:
Why would I store JournalItemTypes in the Redux store if it is static data? All of the apps metadata is in my redux store so it can be easily refreshed from the server. By keeping it in Redux I can treat metadata in the same way as all other data in my synchronisation sagas.
Added clarification after Mika's answer
I need to use the local state because the component is a quite complex input form with all sorts of inputs (input fields, camera, qr-reader, live updated SVG sketch based on input).
A JournalItem in my app is "all or nothing". I.e. if every required field is filled in the user is allowed to save the item. My store is persisted to disk, so I don't want to hit the store more often than needed. So the JournalItem-object (actually an Immutable.map) lives in state until it's ready to be saved.
My selectors are memoized with reselect. This makes my first solution even less impacting on performance. But it still feels wrong.
The component gets updated via props due to other events, so it's re-rendered now and then.
You have a few different options here:
Option 1: the original way
This is the most basic and most 'Redux' way of doing it. If your selectJournalItemType function is moderately light, your app won't suffer much of a performance hit as mapStateToProps is only called when the store is updated according to react-redux docs.
Option 2: the constructor
It is generally recommended to avoid using the Component's state with Redux. Sometimes it is necessary (for example forms with inputs) but in this case it can, and in my opinion should, be avoided.
Option 3: optimizing option 1
If your function is computationally expensive, there are at least a few ways to optimize the original solution.
In my opinion one of the simpler ones is optimizing the react-redux connect. Short example:
const options = {
pure: true, // True by default
areStatesEqual: (prev, next) => {
// You could do some meaningful comparison between the prev and next states
return false;
}
};
export default ContainerComponent = connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
options
)(PresentationalComponent);
Another possibility is to create a memoized function using Reselect