What should be the best practice while refactoring React code here? - reactjs

I'm trying to refactor my React frontend code, basically all the hardcoded strings are to come from CMS and for that I have made a custom hook that fetches the string my components need.
I have a constant file which previously used to refer this string file that contained all the hardcoded strings before, now since I have the hook, how do I use it to replace this string file inside my constants file?
export const SCORES_INFORMATION_BY_SEVERITY_LEVEL: Record<string, IScoreInformation> = {
[DepressionLevels.MinimalDepression]: {
score: '0 - 4',
title: 'No or minimal depression',
description: Strings.minimalDepressionDescription,
},
[DepressionLevels.MildDepression]: {
score: '5 - 9',
title: 'Mild depression',
description: Strings.mildDepressionDescription,
},
[DepressionLevels.ModerateDepression]: {
score: '10 - 14',
title: 'Moderate depression',
description: Strings.moderateDepressionDescription,
}
};
The description key here is what getting referenced from the String file as you can see.
What I thought could be a possible solution:
I decouple this part of the file and put it in the component itself that refers it as obviously I can't use hook in the consts file. The problem with that is that this constant is getting used at multiple places and I will end up repeating my code
Just make few another constants for these strings in the constant file itself and leave it be but I'm not sure if it's the right thing to do.

Related

Property 'length' does not exist on type error on importing array of objects

I am importing this array:
const quotes = [
{ quote: "Design is intelligence made visible.", name: "Alina Wheeler" },
{
quote:
"The public is more familiar with bad design than good design. It is, in effect, conditioned to prefer bad design, because that is what it lives with. The new becomes threatening, the old reassuring.",
name: "Paul Rand",
},
{
quote: "Every great design begins with an even better story.",
name: "Lorinda Mamo",
}
];
into another .tsx file and using it this way:
import * as quotes from "./quotes/quotes";
const quoteLength = quotes.length - 1;
But I'm getting this error: Property 'length' does not exist on type 'typeof import
Any idea how I can fix this? How do I declare that array of objects as a type?
Have you exported the array from the quotes file?
If you have then
call it using import {quotes} from "./quotes/quotes";
You have to export and import file this way, as you can see the below code
export const quotes = [
{
quote: 'Design is intelligence made visible.',
name: 'Alina Wheeler'
},
{
quote:
'The public is more familiar with bad design than good design. It is, in effect, conditioned to prefer bad design, because that is what it lives with. The new becomes threatening, the old reassuring.',
name: 'Paul Rand'
},
{
quote: 'Every great design begins with an even better story.',
name: 'Lorinda Mamo'
}
];
.tsx file
import {quotes} from "./quotes/quotes";
const quoteLength = quotes.length - 1;

React-intl: Why need to define Messages using either <FormattedMessage> Component or defineMessagesAPI function

I currently have the translated English and Japanese .json file in the format:
{
"en": [{
"id": "Cancel",
"defaultMessage": "Cancel"
}, {
"id": "CommonTags",
"defaultMessage": "Common Tags"
}]
"ja": [{
"id": "Cancel",
"defaultMessage": "キャンセル"
}, {
"id": "CommonTags",
"defaultMessage": "共通タグ"
}]}
My question is, why do I need to define the messages now considering that I already have all of these generated and translated? I am simply like to access them in the following way but getting an error:
var messages_ja = require("../../../Resources/Resources.ja2.js.json");
class LocalizedApp extends React.Component {
props: any;
static propTypes: { intl: (object: any, key: string, componentName: string, ...rest: any[]) => Error | null; };
render() {
return (...
<h1>{this.props.intl.formatMessage({ id: messages_ja.Cancel })}</h1>);}}
I get the following error:
[React Intl] An id must be provided to format a message.
Repeating my question:
Do I really need to incorporate the ecosystem for defining messages.
If so, why?
Is it possible to simply access the strings based on
locale from the json, without creating formattedMessages for them.
Thanks in advance.
Answer for question 1:
I'd say yes. You have to choose between using the declarative (e.g.: <FormattedMessage />) or the imperative api (e.g.: intl.formatMessage()).
Answer for question 2:
You could, but then why would you use react-intl then?
(You could say that you only want to use its localization methods for date, numbers, percentage.. which would be ok, but IMHO you'd have much more effort to build your own solution other than using the lib.)
I always prefer to use the declarative API, and it's a good practice to have an ID and a default message. This default message that react-intl complains is actually to help you. It's a fallback for in case you missed one translation, it defaults to this message.
I recommend using the imperative api if you want to reuse labels or if you need to use them outside react components (from my experience, these were the only cases where it could be done). You can also use the babel-plugin-react-intl to auto-extract the labels from your application and make your life pretty much easy!

Meteor inserting into a collection schema with array elements

Hi I created a SimpleSchema for a Mongo collection which has a variable number of sub-documents called measurables. Unfortunately it's been a while since I've done this and I can't remember how to insert into this type of schema! Can someone help me out?
The schema is as follows:
const ExerciseTemplates = new Mongo.Collection('ExerciseTemplates');
const ExerciseTemplateSchema = new SimpleSchema({
name: {
type: String,
label: 'name',
},
description: {
type: String,
label: 'description',
},
createdAt: {
type: Date,
label: 'date',
},
measurables: {
type: Array,
minCount: 1,
},
'measurables.$': Object,
'measurables.$.name': String,
'measurables.$.unit': String,
});
ExerciseTemplates.attachSchema(ExerciseTemplateSchema);
The method is:
Meteor.methods({
addNewExerciseTemplate(name, description, measurables) {
ExerciseTemplates.insert({
name,
description,
createdAt: new Date(),
measurables,
});
},
});
The data sent by my form for measurables is an array of objects.
The SimpleSchema docs seem to be out of date. If I use the example they show with measurables: type: [Object] for an array of objects. I get an error that the the type can't be an array and I should set it to Array.
Any suggestions would be awesome!!
Many thanks in advance!
edit:
The measurable variable contains the following data:
[{name: weight, unit: kg}]
With the schema above I get no error at all, it is silent as if it was successful, but when I check the db via CLI I have no collections. Am I doing something really stupid? When I create a new meteor app, it creates a Mongo db for me I assume - I'm not forgetting to actually create a db or something dumb?
Turns out I was stupid. The schema I posted was correct and works exactly as intended. The problem was that I defined my schema and method in a file in my imports directory, outside both client and server directories. This methods file was imported into the file with the form that calls the method, and therefore available on the client, but not imported into the server.
I guess that the method was being called on the client as a stub so I saw the console.log firing, but the method was not being called on the server therefore not hitting the db.
Good lesson for me regarding the new recommended file structure. Always import server side code in server/main.js!!! :D
Thanks for your help, thought I was going to go mad!

Should I store static configuration in redux?

I am building a react/redux web app and am wondering where I should static configuration information that never changes (while the webapp is running anyway).
This is the data in question
This information is used in different parts of the app, for example: there is a form where you are able to select any item out of the main array, and by doing so populating another select field with properties of the selected array:
<select>Choose an exchange</select>
<select>Choose a market (that is available in the above exchange)</select>
This would lend itself nicely to some reducer logic (that sets state.markets based on what is selected in the first select), but should it filter based on other state in the tree, or just load the data in a closure inside the reducer (keeping everything unrelated outside of state tree)? Or is this not state at all (and should the container load this file in and filter based on a single state.exchange state prop)?
When the form is filled in the result will be handled like:
{exchange: 'a', market: 'b'}
So that would be state too (I guess?)
My understanding of redux is that we should only be storing stateful data in the store, that is, data that is subject to change. Static data by definition does not have state, and therefore does not need to be tracked as such.
As a result, I typically have a /common/app-const.js file where I store these types of static objects. In your case, you can simply move all the static data from exchange.js into a common file that you then import wherever you need it.
/common/app-const.js
export default {
markets: [
{ pair: ['USD', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
{ pair: ['RUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
{ pair: ['EUR', 'BTC'], minimalOrder: { amount: 0.01, unit: 'asset' } },
...
}
I understand your approach however, it would be nice to simply inject your data, by way of connect() via react-redux, however its a bit more straightforward to just import the static data from a file where needed.

Typed literal objects in TypeScript

I have a TS definition file for Ext JS containing function store.add(a : any) (it has many overloads so I guess this is to simplify the d.ts file). I want to pass it a literal object which implements a Person interface:
interface Person
{
name: string;
age: number
}
store.add(<Person>{ name: "Sam" });
This gives me intellisense but unfortunately it is just coercing the literal into a Person, without detecting the missing field. This works as I want:
var p : Person = { name: "Sam" }; // detects a missing field
store.add(p);
But is there a way to do this without a separate variable?
I realise this would be solved with 'fixed' definition files, but I think many Javascript libraries have too many overloads to allow this. I almost need a way to dynamically overload the function definition..! Would generics help here?
Yes generics seem to be the answer. In the definition file changing:
add?( model:any ): Ext.data.IModel[];
to
add?<T>( model:T ): Ext.data.IModel[];
Allows you to call
store.add<Person>({ name: "sam" });
And it correctly shows an error!

Resources