How to store React component in object - javascript

I have an object of all apps:
export const allApps: appInterface[] = [
{
id: uuidv4(),
name: "Minesweeper",
icon: minesweeperIcon,
disabled: false,
},
];
I want to add component property to each object like this:
export const allApps: appInterface[] = [
{
id: uuidv4(),
name: "Minesweeper",
icon: minesweeperIcon,
disabled: false,
component: Minesweeper, //It is imported as import Minesweeper from ../Components/Minesweeper";
},
];
And then I want to display all components in App.js:
allApps.forEach((app)=>{
<div>{app.component}<div> // for eg: <div><Minesweeper/></div>
});
Is this possible to do?

Try as below code it should work.
allApps.map((app)=>{
const { component: Component } = app;
return <Component />;
});

Related

Get Typescript type as value

I have components like these
type TestComponentProps = {
title: string;
}
const TestComponent: React.FC<TestComponentProps> = ({
title,
}) => {
return <div>TestComponent: {title}</div>;
};
type TestComponent2Props = {
body: string;
}
const TestComponent2: React.FC<TestComponent2Props> = ({ body }) => {
return <div>TestComponent2: {body}</div>;
};
I would need an interface that would allow me to configure which component to render and get the props of that particular component
const dataToRender:Array<{
component: TestComponent | TestComponent2,
data: propsOf<component>
}> = [
{
component: TestComponent,
data: { title: '123' }
},
{
component: TestComponent2,
data: { body: 'lorem ipsum' }
}
];
Ideally I'd need to get the props of the particular component in a way "I want to render this component and I can only accept the correct props based on the props of that component"
You can do this, but not with plain typesciprt type annotations. In vue js for particular, for better typing you need to use defineComponent wrapper, that just return it argument (id) but with types.
In you case you can use this function.
function defineComponent<TProps, TModal extends React.ComponentType<TProps>>(x: {
component: TModal & React.ComponentType<TProps>
data: TProps
}) {
return x
}
And use it like so:
const dataToRender = [
defineComponent({
component: TestComponent,
data: { title: "123" },
}),
defineComponent({
component: TestComponent2,
data: { title: "lorem ipsum" }, // error here
}),
] as const

How to pass dynamic params to name route - Vue JS

I have this LayoutVertical.vue parent component:
<script>
import LayoutVertical from "#core/layouts/layout-vertical/LayoutVertical.vue";
import AppCustomizer from "#core/layouts/components/app-customizer/AppCustomizer.vue";
import { $themeConfig } from "#themeConfig";
import navMenuItems from "#/navigation/vertical";
export default {
components: {
AppCustomizer,
LayoutVertical,
},
data() {
return {
showCustomizer: $themeConfig.layout.customizer,
navMenuItems,
};
},
};
</script>
This navMenuItems property contained:
export default [
{
header: "Projects",
},
{
title: "Import",
route: {
name: "project-import",
params: { token: token },
},
icon: "SettingsIcon",
},
];
And the route for this:
{
path: "/project/import/view/:token",
name: "project-import",
props : true,
component: () =>
import("#/views/apps/projects/project-import/ProjectImport.vue"),
},
Now, I have another compnent called AppNavbarVerticalLayout.vue which is child component of that parent. In this component I have a onChange methods called chooseProject. From this method I can get a token value.
My question is how can I pass this token value to that navMenuItems property's params?
Can I set a params for a specific name route?

Redundant navigation to current location in VueJs

I have app with a search function and the initial search works from the homepage. When I try to search again, after the initial results have been fetched and loaded, nothing is returned and I have to go to another page in the app to search again. The search is done through a navbar which appears on every page and the results are returned to a specific view page via an unordered list. I would like to be able to search again after the list page is loaded.
router.js file:
The results are loaded on the "Beers" page.
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About,
},
{
path: '/beer/:beerId',
name: 'BeerView',
component: BeerView,
props: true
},
{
path: '/beers=?:search',
name: 'Beers',
component: Beers,
props: true
}
]
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
duplicateNavigationPolicy: 'ignore'
})
export default router
The page to which the results are loaded, aka "Beers":
<script>
import axios from "axios";
export default {
name: "Beers",
props: ["beers"],
data() {
return {
beersData: this.beers,
};
},
mounted() {
if (this.beers === null || this.beers === undefined) {
axios.get(process.env.VUE_APP_BEER_API_URL).then((data) => {
this.beersData = data.data;
this.$router.replace({ name: "Beers", params: {search: this.$route.params.search} }).catch(()=>{});
});
}
},
methods: {
navigate(id) {
this.$router.push({ name: "BeerView", params: { id: id } });
},
},
};
</script>
The NavBar component:
<script>
import { ref } from "#vue/composition-api";
import axios from "axios";
export default {
name: "Navbar",
props: ["search"],
methods: {
async getBeer(search) {
const res = await axios.get(`${process.env.VUE_APP_BEER_API_URL}?q=${search}`);
this.$router.push({ name: "Beers", params: { beers: res.data} }).catch(()=>{});
},
},
setup({ search }, ) {
const beerQuery = ref(search);
return {
beerQuery,
handleSubmit(event) {
event.preventDefault();
this.getBeer(beerQuery.value);
console.log(beerQuery.value);
},
handleChange(event) {
beerQuery.value = event.target.value;
},
};
},
};
</script>

Trying to map over passed array of objects property in React

Started learning React and JS not too long ago.
I have a parent class 'App' that gets a an array of objects 'data' from data.js. App.js is sending that 'data' property down to the 'BookList' class. I am trying to map over said property in the BookList class and save elements in 'mappedBooks' but keep getting this error:
TypeError: this.props.books.map is not a function
DATA.JS:
const data = [
{
id: 1,
title: `The Pragmatic Programmer`,
author: `David Thomas, Andrew Hunt`,
img: `https://images-na.ssl-images-amazon.com/images/I/51cUVaBWZzL._SX380_BO1,204,203,200_.jpg`
},
{
id: 2,
title: `HTML and CSS: Design and Build Websites`,
author: `Jon Duckett`,
img: `https://images-na.ssl-images-amazon.com/images/I/31aX81I6vnL._SX351_BO1,204,203,200_.jpg`
},
{
id: 3,
title: `Coding All-in-one For Dummies`,
author: `Nikhil Abraham`,
img: `https://images-na.ssl-images-amazon.com/images/I/51RXaV0MGzL._SX397_BO1,204,203,200_.jpg`
},
{
id: 4,
title: `Learning React`,
author: `Alex Banks, Eve Porcello`,
img: `https://images-na.ssl-images-amazon.com/images/I/51FHuacxYjL._SX379_BO1,204,203,200_.jpg`
},
{
id: 5,
title: `Learning Web Design`,
author: `Jennifer Robbins`,
img: `https://images-na.ssl-images-amazon.com/images/I/51iVcZUGuoL._SX408_BO1,204,203,200_.jpg`
},
{
id: 6,
title: `JavaScript and JQuery: Interactive Front-End Web Development`,
author: `Jon Duckett`,
img: `https://images-na.ssl-images-amazon.com/images/I/41y31M-zcgL._SX400_BO1,204,203,200_.jpg`
},
{
id: 7,
title: `Head First JavaScript Programming`,
author: `Eric Freeman, Elisabeth Robson`,
img: `https://images-na.ssl-images-amazon.com/images/I/51qQTSKL2nL._SX430_BO1,204,203,200_.jpg`
},
{
id: 8,
title: `Learning Redux`,
author: `Daniel Bugl`,
img: `https://images-na.ssl-images-amazon.com/images/I/41gxBZ8GNpL._SX403_BO1,204,203,200_.jpg`
},
{
id: 9,
title: `Node.js 8 the Right Way`,
author: `Jim Wilson`,
img: `https://images-na.ssl-images-amazon.com/images/I/51t44mzlCaL._SX415_BO1,204,203,200_.jpg`
},
{
id: 10,
title: `PostgreSQL: Up and Running`,
author: `Regina Obe`,
img: `https://images-na.ssl-images-amazon.com/images/I/51FSjiYDfpL._SX379_BO1,204,203,200_.jpg`
},
{
id: 11,
title: `Fundamentals of Web Development`,
author: `Randy Connolly, Ricardo Hoar`,
img: `https://images-na.ssl-images-amazon.com/images/I/51xEzGTH6lL._SX402_BO1,204,203,200_.jpg`
},
{
id: 12,
title: `Web Design Playground`,
author: `Paul McFedries`,
img: `https://images-na.ssl-images-amazon.com/images/I/41-6F+RDbIL._SX258_BO1,204,203,200_.jpg`
}
]
export default data;
APP.JS
import React, {Component} from 'react'
import './App.css';
import BookList from './Components/BookList';
import Header from './Components/Header'
import Shelf from './Components/Shelf';
import data from './data'
class App extends Component {
constructor(){
super()
this.state ={
books : {data}
}
}
render(){
return (
<div className="App">
<Header/>
<BookList books={this.state.books}/>
<Shelf/>
</div>
);
}
}
export default App;
and BOOKLIST.JS:
import React, {Component} from 'react'
class BookList extends Component{
render(){
let mappedBooks = this.props.books.map(function(element){
return {element}
})
return(
<div className = 'BookList'>
<h1>list</h1>
</div>
)
}
}
export default BookList
in Data.js you've got
export default data;
and data is an array. So when you import data in App.js it's an array.
Try running this code snippet to get a better idea of what's going on here:
let data = [1,2,3,4]
console.log('when data is an array')
console.log('{data} is', {data})
data = {
'data': [1,2,3,4]
}
console.log('when data is an object with a property called data pointing to an array')
console.log('{data} is', {data})
console.log('but if you call a function and pass in data (as an object with data as a named property pointing to an array), you can use the curly braces to pull the array out of the object using destructuring')
function destructureData({data}) {
console.log(data)
}
destructureData(data)
So, when you do this:
this.state = {
books: { data }
}
it's actually an object property shorthand that's interpreted (in ES6) as this:
this.state = {
books: { data: data }
}
If you actually want this.state.books to be the array you imported from data.js then you set it directly:
this.state = {
books: data
}
Or, using that object property shorthand, and the fact that you've got data as a default export, you could change the import to this:
import books from './data'
And then do this:
this.state = {
books
}
If you'd like to read more about the destructuring syntax–where you use curly braces to pull data out of an object or an array–this article on MDN is a good read.

Update translation without page refresh (i18next with react)

My _nav.js file:
import i18n from '../../services/Translator';
export default {
items: [
{
name: i18n.t('DASHBOARD'),
url: '/dashboard',
icon: 'icon-speedometer',
},
{
name: i18n.t('SCHEDULE'),
url: '/schedule',
icon: 'icon-calendar',
},
{
name: i18n.t('USERS'),
url: '/users',
icon: 'icon-user',
},
{
name: i18n.t('LEASING_COMPANY'),
url: '/company',
icon: 'icon-organization',
},
],
};
My component:
import { translate } from 'react-i18next';
import nav from '../Sidebar/_nav';
/...
render() {
const test = nav.items.map((item) => {
return <li key={item.url}>{item.name}</li>;
});
return (
<ul>{test}</ul>
);
}
The problem is I don't get my text translated when I change language. My browser need to be refreshed to apply translation. Anyone know how to get translation done without page refresh?
Edit: This is my Translator service:
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import en from '../../lang/en';
import vn from '../../lang/vn';
import env from '../../config/env';
i18n
.use(LanguageDetector)
.init({
// we init with resources
resources: {
en,
vn,
},
fallbackLng: env.defaultLanguage,
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
keySeparator: false, // we use content as keys
react: {
wait: true,
},
});
export default i18n;
I also put my change language button on the Header component in my page.
Can't work like this...you assign translations to objects in the array inside _nav.js
Those will be strings no way any code will ever update those values you will need to regenerate those on language change or:
import i18n from '../../services/Translator';
export default {
items: [
{
name: 'DASHBOARD',
url: '/dashboard',
icon: 'icon-speedometer',
},
{
name: 'SCHEDULE',
url: '/schedule',
icon: 'icon-calendar',
},
{
name: 'USERS',
url: '/users',
icon: 'icon-user',
},
{
name: 'LEASING_COMPANY',
url: '/company',
icon: 'icon-organization',
},
],
};
and
import { translate } from 'react-i18next';
import nav from '../Sidebar/_nav';
/...
render() {
const test = nav.items.map((item) => {
return <li key={item.url}>{t(item.name)}</li>;
});
return (
<ul>{test}</ul>
);
}

Categories