how to render components reading it from json - reactjs

Example I have some json data and I want to render components as described in json
const myJson = {
hbox : {icon1 : "image",file_name : "text", icon2 : "image" }
}
import React from 'react';
import { Image, Text, View } from 'react-native';
const components = {
icon: Image,
text: Text
};
function SimpleComponent(componentType) {
const SpecificStory = components[componentType];
return <SpecificStory />;
}
how to render this components inside View component recursively
function readJson (json) {
let arr = Object.keys(json);
for (let i in arr){
if(typeof json[arr[i]] == 'string'){
SimpleComponent(json[arr[i]]);
} else { readJson(json[arr[i]])}
}
}
render () {
return ( <View>{readJson(myJson)}</View>)
}
is it possible like I wrote above

You could make a landing component, suppose GeneralComponent.
Use something like this: <GeneralComponent type="ComponentType" data={allDataYouNeedInCop}/>
In onCreate of the GeneralComponent, check what is written in props.type, and act accordingly.

You can do it but you will have a lot of cases.
1- Recursive function
So about recursive function (readJson) you can use map function instead.for exemple :
let result = myJson.map( (elem) => {
return SimpleComponent(elem);
});
render () {
return ( <View>{result}</View>)
}

Related

Convert to if/else from nested ternary in lit-html

how to write below code lit html
I am new to lit html , i try to convert the below code to if/else instead of nested ternary
render() {
return this.html`
${this.data ? this.html`<comp data={this.data}></comp>`
: data1 && data1.test === 'valid' && valueCheck ? this.html`
<comp2 data={this.data2} ></comp2>
`
: this.html`
<comp1 data={this.data1} ></comp1>
`} `;}
Need to convert simple if else
I understand you want to use this to render components. Normally, when I have complex validations if/elses to do, I do them outside the render part and attribute it to a variable.
let dataToRender = undefined;
if(this.data){
dataToRender = this.html`<comp data={this.data}></comp>`
} else if(data1 && data1.test === 'valid' && valueCheck){
dataToRender = <comp2 data={this.data2} ></comp2>
} else {
dataToRender = <comp1 data={this.data1} ></comp1>
}
And, then, on the render function simply:
render(
${dataToRender}
)
You usually want to enumerate the value based on the logic, it's more readable and maintainable in the future if your logic grows.
You can also combine the built-in choose directive to render one of many templates based on the key value.
import { LitElement, html } from "lit";
import { choose } from "lit/directives/choose.js";
enum RenderOptions {
COMP,
COMP_1,
COMP_2
}
class MyElement extends LitElement {
// mocks
data = {}
data1 = { test: "valid" }
data2 = {}
valueCheck = true
render() {
return html`
${choose(this._conditionalRender(), [
[RenderOptions.COMP, () => html`<comp data={this.data}></comp>`],
[RenderOptions.COMP_1, () => html`<comp1 data={this.data1}></comp1>`]
[RenderOptions.COMP_2, () => html`<comp2 data={this.data2}></comp2>`],
],
() => html`<h1>Error</h1>`)}
`;
}
private _conditionalRender(): RenderOptions {
if (this.data) {
return RenderOptions.COMP
}
if (this.data1 && this.data1.test === 'valid' && this.valueCheck) {
return RenderOptions.COMP_2
}
return RenderOptions.COMP_1
}
}
// implementations of...
// comp
// comp1
// comp2

How to render repeatedly a react component till I find some specific object?

I am working on #inlet/react-pixi. I have a React component that will eventually resolve to a Pixi Graphics object.
import React, { useCallback } from 'react';
import { Graphics } from '#inlet/react-pixi';
function Rectangle(props) {
const draw = useCallback((g) => {
g.clear();
g.beginFill(props.color);
g.drawRect(props.x, props.y, props.width, props.height);
g.endFill();
}, [props]);
return <Graphics draw={draw} />;
}
The Rectangle component on render will give a Graphics component which on render will give a Graphics object as shown below.
import { Graphics as PixiGraphics } from 'pixi.js'
import { applyDefaultProps } from '../utils/props'
import invariant from '../utils/invariant'
const Graphics = (root, { geometry }) => {
invariant(!geometry || geometry instanceof PixiGraphics, `Graphics geometry needs to be a \`PIXI.Graphics\``)
const g = geometry ? new PixiGraphics(geometry.geometry) : new PixiGraphics()
g.applyProps = (instance, oldProps, newProps) => {
const { draw, geometry, ...props } = newProps
let changed = applyDefaultProps(instance, oldProps, props)
if (oldProps.draw !== draw && typeof draw === 'function') {
changed = true
draw.call(g, g)
}
return changed
}
return g
}
export default Graphics
My question is given any arbitrary component c passed to a function f, how do I keep rendering it till I get a g object?
function f(c) {
// expected code
let obj = render(c)
while (!Graphics.prototype.isPrototypeOf(obj) {
obj = render(obj);
}
return obj;
}

Passing fetched data to context-Provider in react

I am fetching data from a English language dictionary API and creating a front end in react JS. The code works if I render out all components in the Form.js but I am trying to pass returned data to the wordDataContext to create components separately.
import React, {useEffect, useState , useContext } from 'react';
import {UserContext} from '../context/UserContext';
import {WordContext,WordProvider} from '../context/WordContext';
const getWord = async() => {
if (word !== '') {
setWord(word)
try {
const response = await fetch(`https://mydictionaryapi.appspot.com/?define=${word}`)
const data = await response.json()
iterateObject(data)
setWordData(data) // pass to context
console.log('word data', wordData)
} catch(error) {
let message = "Word NOT Found - Check spellings or connection"
setMeaning(message)
console.log(error)
}
}
}
I am then iterating over the returned dictionary object to extract definitions(meanings), synonyms and example sentence etc.
function iterateObject(data) {
for (var item in data) {
if (typeof(data[item]) == "object"){
if (item === "synonyms"){
var synonyms = data[item]
setSynonyms(synonyms)
}
iterateObject(data[item])
}
else
{
if (item === "definition") {
var meaning = data[item]
setMeaning(meaning)
}
if (item === "example"){
var example = data[item]
setExample(example)
}
}
}
}
I can render out components from iteration but I want to pass the dictionary object ( or iterated items ) to a global wordDataContext to make separate components. Here is the code for my wordDataContext and Provider,
import React, {useState, createContext } from 'react';
export const WordContext = createContext([ [{}], () => {}])
export const WordProvider= (props) => {
const [wordData , setWordData] = useState({ word:'' , meaning:'', synonyms:{} , example:'' })
return(
<WordContext.Provider value={[wordData, setWordData]}>
{props.children}
</WordContext.Provider>
)
}
Unfortunately, the returned object is not getting passed to the WordDataContext I have tried doing so after fetching the data in API call function and also when iterating but only get an empty array

Convert react class to react function

Hi so I have two files and i want to convert one of them into a react functional component. The first one is PuzzleGrid and it will call the function Grid.getMatrix()
export const PuzzleGrid = () => {
const newMatrix = GridLib.getMatrix();
}
and the next is Gridlib which is a react class :
export class GridLib {
static getMatrix() {
return Array(6).fill(Array(6).fill(0));
}
}
I want to be able to convert the class into a function, this is what i have, however i am getting an error. does anyone understand why?
export const GridLib = () => {
GridLib.getMatrix = {
Array(6).fill(Array(6).fill(0));
}
}
You can simply return the results of the getMatrix method:
export const GridLib = () => {
return Array(6).fill(Array(6).fill(0));
}
However, this will cause a problem for your PuzzleGrid component, as it depends on GridLib having a getMatrix method. You would have to simply have PuzzleGrid return a GridLib for it to work as such:
export const PuzzleGrid = () => {
return <GridLib />
}
However this pattern is a bit silly and repetetive. I feel like there must be more going on to your question, but you may have reduced it down too much and stripped away some important details. What is the larger context of this issue?
Just use a function properties to declare a "static method"
export const GridLib = () => {
return <View/> ;
}
GridLib.getMatrix = () => {
return Array(6).fill(Array(6).fill(0));
}

How to show dinamically a react component

I'm working in a React project and I need to render some Components based on a layout.
--asumme you have an array that tells you the components you need to render:
Layout1 = ['Events', 'Photo', 'News']
--And a function that, depends on the module, render the especific component with some data:
layout1.forEach(function(layout) {
someFuncions(layout, somedata);
});
someFunction = (layout, data) => {
layout.forEach( function(Comp) {
if(Comp == 'Events') {
return (<Events module-data={data} />)
} else if(Comp == 'Photo') {
return (<Photo module-data={data} />)
} else if(Comp == 'News') {
return (<News module-data={data} />)
}
});
}
-- Since it is possible to have many components I want to find a way to avoid the "if" function to determine what component should I render.
How can I achieve this? Thanks a lot guys
You can use a switch similar syntex but maybe a little cleaner.
switch(comp) {
case 'Events':
return (<Events module-data={data} />)
case 'Photo':
return (<Photo module-data={data} />)
case 'News':
return (<News module-data={data} />)
}
You can pass the component in the array directly.
import Events from 'path/to/Events'
import Photo from 'path/to/Photo'
import News from 'path/to/News'
Layout1 = [Events, Photo, News]
And then wherever you call the function.
From your original question, it seems like the layout1 in your question is an array of Layout1 like arrays.
layout1.forEach(function(layout) {
someFuncions(layout, somedata);
});
someFunction = (layout, data) => {
// returning from forEach won't result in anything. you probably want to map
layout.forEach( function(Component) {
return (<Component module-data={data} />)
})
}
I would approaching it by creating a map for your components, then doing a lookup when rendering.
const components = {
Events, // Shorthand for 'Events': Events
Photo,
News
};
const layout = ['Events', 'Photo'];
const someFunction = (layout, data) =>
layout.map((name) => {
const Component = components[name];
return <Component module-data={data} />;
});
What about using a javascript object that maps the layout to the desired component? This way, it's clear that you intend to render a different component depending on the layout.
See the following example:
const someFunction = (layout, data) => {
const componentMap = {
'Events': <Events module-data={data} />,
'Photo': <Photo module-data={data} />,
'News': <News module-data={data} />
}
return componentMap[layout];
}

Resources