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
Related
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 have the following in my project...
const basicRecords = reactive([]);
It basically just houses an array of objects. I want to be able to refresh this array, that would require me to remove all of the records and add them back. To do this I have done the following...
basicRecords.splice(0);
basicRecords.push(...recordResult.data);
This seems to work but also seems super hacky.
What is the proper way to reset a reactive array in Vue3?
Try to use Object.assign to keep it reactive :
const basicRecords = reactive([]);
Object.assign(basicRecords, recordResult.data)
or define basicRecords as inner field of reactive state :
const state = reactive({basicRecords : []});
state.basicRecords = recordResult.data
or with ref :
const basicRecords = ref([]);
basicRecords.value = recordResult.data
I have a functional component that manages a question that can come from two sources.
A props value comes in indicating the source.
When the source changes, I want to create a new question model object with the new source.
Since I'm doing something like this:
const [questionModel, setQuestionModel ] = useState(new QuestionModel(questionSource));
For some reasons it thinks, "Oh, I've already got one of those questionModel's. I don't need to make a new one".
So all the old stuff stays there.
If I try to do something like:
setQuestionModel(new QuestionModel(questionSource));
Then it complains about:
Invariant Violation: Too many re-renders. React limits the number of
renders to prevent an infinite loop.
I get that infinite loops are bad, but I'm not sure how to make this work in ReactJS functions with hooks.
Back when I was using classes, I could specify something once in the constructor and then adjust it again in the render(). But now that the render is mixed in with the other code for the function, how do I re-render it with the new source?
Is there a force re-render when the props change? I thought it would do that if a prop changed ... but it doesn't.
I don't know how your props changes but I saw sometimes, that the following misunderstanding creates sometimes problems, where the developer thinks "I changed the object, so why my component doesn't rerender?":
When you create a new object like:
const user = { name: "john" };
You created an object that, has a property that points to the value "john" like this:
user -> { } -- name --> "john"
user points on an object and when you make name, point to a different value by:
user.name = "bob"
than user still points to the same object and to react it's the same object
but when you do
user = { ...user, name: "bob" };
then you would assign a new object and now it's a different object.
Look at using useEffect with a dependency of the prop that is being passed in. Within the effect, set the new question type in local state.
https://reactjs.org/docs/hooks-effect.html
Like this...
interface Props {
source: QuestionSource
}
export function QuestionsModal(props: Props) {
const [questionModel, setQuestionModel] = useState<QuestionModel>(new QuestionModel(questionSource))
useEffect(() => {
setQuestionModel(new QuestionModel(questionSource))
}, props.source)
}
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;
};
I have a mutator that attempts to make the follow update:
state.forms[1].data.metrics.push(newArrayItem)
forms is an object with 1 as a key
metrics is an array
For some reason, Vuex successfully updates, but components don't react to this change.
I was reading about Vue.set() on https://v2.vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats
But I'm not sure how to apply it, or even if it's the right answer at all here.
Thanks for the help.
this.$forceUpdate is working, which is a bit strange because the component loading the data uses computed properties.
Form state is setup initially like so:
const state = {
forms: {}
};
New forms are pushed like so:
state.forms[id] = { formName: payload.formName, data: {metrics: []}};
And new metrics are added like so:
var result = getParent(state, payload.path);
result.metricParent.data.metrics.push({ id: newMetricId(state, result.formId), ...payload.metric });
Your problem is not with pushing to arrays. Your problem is in this line:
state.forms[id] = { formName: payload.formName, data: {metrics: []}};
Because you are creating a new property of state.forms without using Vue.set(), the form is not reactive, so when you push to the metrics array later, it's not recognized.
Instead, you should do this:
Vue.set(state.forms, id, { formName: payload.formName, data: {metrics: []}});
Then, pushing to state.forms[id].data.metrics should work as expected.
Vue setup reactive data looking for how the state/data is setup, by example if in a regular component you define the data like {x: {y: 10}} and you change the data somehow this.x.y = 20; it’s going to work, because Vue make the object with that structure reactive (because is the setup structure) based on that if you try to do, this.x.z = 10; not works because “z” not exists, and you need to tell to Vue that you need to make it reactive, this is when this.$set(this.x, “z”, 10); enters, it’s basically saying “make this data reference in position ‘z’ reactive”, after this point direct calls to this.x.z = ? works, in vuex the same happens, use Vue.set(state.forms, 1, { formName: payload.formName, data: {metrics: []}}); after that the reference to state.forms[1] (including sub data) is now reactive!