Capitalize ${NAME} in File and Code Templates - intellij-idea

Problem
In Preferences -> Editor -> File and Code Templates I have a template for React with:
import React from 'react';
class ${NAME} extends React.Component {
render() {
return (
<div>
#[[$END$]]#
</div>
);
}
}
export default ${NAME};
Is there a way to capitalize the ${NAME}?
We have a convention of naming our files starting with a lowercase but in React components are meant to be capitalized.
Additional Information
I'm aware of the IntelliJ's ability to refactor and that you can use a Live Templates to accomplish this but I would like to remove this extra step :).
This is possible in Live Templates where you can define and reference a expression like capitalize(fileNameWithoutExtension()) but I couldn't find anywhere to define expressions in File and Code Templates.

So after doing some research I came up with this:
import React from 'react';
#set($capitalizedFilename = $NAME.substring(0,1).toUpperCase() + $NAME.substring(1))
class $capitalizedFilename extends React.Component {
render() {
return (
<div>
#[[$END$]]#
</div>
);
}
}
export default $capitalizedFilename;

An IntelliJ IDEA file template is a Velocity template. Velocity allows you to use standard String methods on variables (see this question for some examples).

Here is all cases for WebStorm File template:
#set($NAME_CAP = $NAME.substring(0,1).toUpperCase() + $NAME.substring(1))
#set($NAME_LOW = $NAME.substring(0,1).toLowerCase() + $NAME.substring(1))
#set($NAME_UPPER = $NAME.toUpperCase())

Velocity's StringUtils is also available:
#set($NAME_CAPITALIZED = ${StringUtils.capitalizeFirstLetter($NAME)})
import React from 'react';
class ${NAME_CAPITALIZED} extends React.Component {
// ...
}

Related

Vue 3 use dynamic component with dynamic imports

I use Vue 3 and I have a dynamic component. It takes a prop called componentName so I can send any component to it. It works, kind of.
Part of the template
<component :is="componentName" />
The problem is that I still need to import all the possible components. If I send About as a componentName I need to import About.vue.
Part of the script
I import all the possible components that can be added into componentName. With 30 possible components, it will be a long list.
import About "#/components/About.vue";
import Projects from "#/components/Projects.vue";
Question
It there a way to dynamically import the component used?
I already faced the same situation in my template when I tried to make a demo of my icons which are more than 1k icon components so I used something like this :
import {defineAsyncComponent,defineComponent} from "vue";
const requireContext = require.context(
"#/components", //path to components folder which are resolved automatically
true,
/\.vue$/i,
"sync"
);
let componentNames= requireContext
.keys()
.map((file) => file.replace(/(^.\/)|(\.vue$)/g, ""));
let components= {};
componentNames.forEach((component) => { //component represents the component name
components[component] = defineAsyncComponent(() => //import each component dynamically
import("#/components/components/" + component + ".vue")
);
});
export default defineComponent({
name: "App",
data() {
return {
componentNames,// you need this if you want to loop through the component names in template
};
},
components,//ES6 shorthand of components:components or components:{...components }
});
learn more about require.context

vue-class-component syntax with typescript

The example on https://github.com/vuejs/vue-class-component (for the component syntax that's new in vuejs3) but I'm using straight type script instead of babel. I therefore tried:
<script lang="ts">
import Vue from "vue"
import Component from "vue-class-component"
#Component({
props: {
propMessage: String
}
})
export default class MyComponent extends Vue {
helloMsg = "Hello, " + this.propMessage
}
</script>
Unfortunately, this.propMessage can't be found. How do I have to change the syntax to make it found?
I would guess this.props.propMessage would work (but i can't test it right now) and you may have already tried.
I recommend you using #Prop decorator from vue-property-decorator which provide a clearer syntax on the long-end.
It would give something like :
#Component
export default class MyComponent extends Vue {
#Prop() propMessage !: string;
helloMsg = "Hello, " + this.propMessage;
}
Good luck

Vue.js how to load dependent components

Vue.js : how to load dependent components?
From router currently using component as follows:
import A from './A';
export default {
components : {
'new-comp-A' : NewCompA
}
}
...
But this renders the template before import causing errors. Is there a better way for loading dependencies?
The template uses the - did you register the component correctly.
Your casing is incorrect. Use either 'NewCompA' or 'new-comp-a' for the name.
In fact, it would be even easier to use
import NewCompA from 'wherever/the/component/is/defined'
export default {
components: {
NewCompA
}
}
Your template can then use either
<NewCompA></NewCompA>
<!-- or -->
<new-comp-a></new-comp-a>
See https://v2.vuejs.org/v2/guide/components-registration.html#Name-Casing
After looking at your code again, it does not seem normal. You are assigning the variable A to your component, but trying to import it with the variable NewCompA..
You need to change the following:
From this:
import A from './A';
export default {
components : {
'new-comp-A' : NewCompA
}
}
...
To this:
import A from './A';
export default {
components : {
'NewCompA' : A
}
}
...
and use it like this:
<new-comp-a>

What is the <{}> syntax after extends Component?

I started a new project today using React Native 0.51.0 and noticed that the class syntax for the default project file had something new added, the <{}> syntax after extends Component:
export default class App extends Component<{}> {
...
}
I tried doing research but most search engines ignore special characters even with exact string matching, so trying to find out what this syntax is has proved to be difficult. I did some testing and was able to figure out that this change appeared in v0.49.0. The release notes make no mention of what this added syntax does though.
A lot of vague keyword searching and reading leads me to believe that this may be syntax related to TypeScript, but being unfamiliar with the language, I'm at a loss as to how to search and find out more about the syntax without knowing what the proper term for it is. Could anyone tell me what the name of the syntax and what it does? Specifically with regards to React Native.
It is related to Flow typings for the props you will receive in the component. Component<{}> would mean that you don't expect the component to receive props.
With Flow and React.Component, you can define types for props and state (see React$Component type declaration for details).
Example from Flow documentation about React components
import * as React from 'react';
type Props = { /* ... */ };
type State = {
count: number,
};
class MyComponent extends React.Component<Props, State> {
state = {
count: 0,
};
componentDidMount() {
setInterval(() => {
this.setState(prevState => ({
count: prevState.count + 1,
}));
}, 1000);
}
render() {
return <div>Count: {this.state.count}</div>;
}
}
<MyComponent />;

How to use global variables in React Native?

In React Native I want to use global variables when I am moving between different screens
Can anyone help me how to achieve it?
The global scope in React Native is variable global. Such as global.foo = foo, then you can use global.foo anywhere.
But do not abuse it! In my opinion, global scope may used to store the global config or something like that. Share variables between different views, as your description, you can choose many other solutions(use redux,flux or store them in a higher component), global scope is not a good choice.
A good practice to define global variable is to use a js file. For example global.js
global.foo = foo;
global.bar = bar;
Then, to make sure it is executed when project initialized. For example, import the file in index.js:
import './global.js'
// other code
Now, you can use the global variable anywhere, and don't need to import global.js in each file.
Try not to modify them!
Try to use global.foo = bar in index.android.js or index.ios.js, then you can call in other file js.
You can use the global keyword to solve this.
Assume that you want to declare a variable called isFromManageUserAccount as a global variable you can use the following code.
global.isFromManageUserAccount=false;
After declaring like this you can use this variable anywhere in the application.
You can consider leveraging React's Context feature.
class NavigationContainer extends React.Component {
constructor(props) {
super(props);
this.goTo = this.goTo.bind(this);
}
goTo(location) {
...
}
getChildContext() {
// returns the context to pass to children
return {
goTo: this.goTo
}
}
...
}
// defines the context available to children
NavigationContainer.childContextTypes = {
goTo: PropTypes.func
}
class SomeViewContainer extends React.Component {
render() {
// grab the context provided by ancestors
const {goTo} = this.context;
return <button onClick={evt => goTo('somewhere')}>
Hello
</button>
}
}
// Define the context we want from ancestors
SomeViewContainer.contextTypes = {
goTo: PropTypes.func
}
With context, you can pass data through the component tree without having to pass the props down manually at every level. There is a big warning on this being an experimental feature and may break in the future, but I would imagine this feature to be around given the majority of the popular frameworks like Redux use context extensively.
The main advantage of using context v.s. a global variable is context is "scoped" to a subtree (this means you can define different scopes for different subtrees).
Do note that you should not pass your model data via context, as changes in context will not trigger React's component render cycle. However, I do find it useful in some use case, especially when implementing your own custom framework or workflow.
Set up a flux container
simple example
import alt from './../../alt.js';
class PostActions {
constructor(){
this.generateActions('setMessages');
}
setMessages(indexArray){
this.actions.setMessages(indexArray);
}
}
export default alt.createActions(PostActions);
store looks like this
class PostStore{
constructor(){
this.messages = [];
this.bindActions(MessageActions);
}
setMessages(messages){
this.messages = messages;
}
}
export default alt.createStore(PostStore);
Then every component that listens to the store can share this variable
In your constructor is where you should grab it
constructor(props){
super(props);
//here is your data you get from the store, do what you want with it
var messageStore = MessageStore.getState();
}
componentDidMount() {
MessageStore.listen(this.onMessageChange.bind(this));
}
componentWillUnmount() {
MessageStore.unlisten(this.onMessageChange.bind(this));
}
onMessageChange(state){
//if the data ever changes each component listining will be notified and can do the proper processing.
}
This way, you can share you data across the app without every component having to communicate with each other.
If you just want to pass some data from one screen to the next, you can pass them with the navigation.navigate method like this:
<Button onPress={()=> {this.props.navigation.navigate('NextScreen',{foo:bar)} />
and in 'NextScreen' you can access them with the navigation.getParam() method:
let foo=this.props.navigation.getParam(foo);
But it can get really "messy" if you have more than a couple of variables to pass..
The way you should be doing it in React Native (as I understand it), is by saving your 'global' variable in your index.js, for example. From there you can then pass it down using props.
Example:
class MainComponent extends Component {
componentDidMount() {
//Define some variable in your component
this.variable = "What's up, I'm a variable";
}
...
render () {
<Navigator
renderScene={(() => {
return(
<SceneComponent
//Pass the variable you want to be global through here
myPassedVariable={this.variable}/>
);
})}/>
}
}
class SceneComponent extends Component {
render() {
return(
<Text>{this.props.myPassedVariable}</Text>
);
}
}