Render React Native Elements from JSON - json

I have searched around...can't quite find what I'm looking for, so I appreciate any help! Here is what I am going for:
I am building a CMS-like setup for a React Native app. This is so that an admin of an app can login to the CMS dashboard, and update a page/view of the app without having to go into the hardcode. I would like them to be able to choose from a pre-set list of components and be able to drag-and-drop them into the app, in whatever order they would want and be able to update the content and colors, etc. Let me provide an example...
There is a home page that I imagine having a rotating banner at the top, then a button for a information modal, then a set of menu links to go to sub-child pages.
So what I think, development-wise, is to give the app admin a WYSIWYG type of setup, and to store the result of this in the Database. It could store in the database as:
<RotatingBanner />
<Modal />
<ContentMenu>
<ContentMenuLink title="About" />
<ContentMenuLink title="Competitive" />
<ContentMenuLink title="Recreational" />
<ContentMenuLink title="Tournaments" />
<ContentMenu />
Right now, when I try to render this into a screen, I continue to have it render that as the actual words vs the components they are representing if that makes sense. So the page looks just like the code block above, instead of seeing a rotating banner and modal, etc.
I have tried a tool to convert HTML into React Native elements...does anyone know how I can convert a fetched JSON that would look like:
{content: "<RotatingBanner /><Modal /><ContentMenu>...."}
and have it create the real components in the render function? Any other thoughts or ideas/advice on creating a CMS like this are greatly appreciated if you would like.
Thanks!

Let's say your have this JSON:
const data = {
"components": [
{"name": "component1", props: {"hello": "world"}},
{"name": "component2", props: {"color": "red"}},
]
}
Make your components and then reference them in an Object (map):
import Component1 from './Component1'
import Component2 from './Component2'
const COMPONENT_MAP = {
component1: Component1,
component2: Component2,
}
Then make your wrapper component:
const Wrapper = ({data}) => (
<View>
{data.components.map(({name, props}) => {
const Component = COMPONENT_MAP[name]
return <Component {...props} />
}}
</View>
)
VoilĂ  :)
<Wrapper data={data} />

I would recommend using Array's to save and render multiple childrens
const Component1 = () => <Text>One</Text>
const Component2 = () => <Text>One</Text>
const childs = [
Component1,
Component2
]
return childs
React is able to render arrays as they are.
Other possible solution could be,
return Object.keys(child).map(item => childs[item] )

A quick solution can be react-native-dynamic-render
Also, you can render nested components with that.
A complete example is here

Related

Conditionally make a page read-only using react

I want to create a React webpage that has both editable and read-only versions, the whole page not just a few elements on the page. A version is displayed to the user based on user id and other conditions. How do I do it?
The only straight forward way I know is to create 2 pages one editable and one read-only and based on the condition show the appropriate version (html page) to the user.
Is there a better and smarter way to do this? Like can I create just one page for both versions and toggle the mode based on the condition to the users?
Your question should have provided an example of some code you had tried but based on the description, very rough example below of one of many possible solutions.
Suppose EditView component is your page and you are able to pass a value for permission based on whatever credential you need to apply.
Then you have a component, ExampleField that takes the permission and displays either an input or static text. A collection of multiple of these fields is mapped from a theoretical array of data that you'll have to fetch from somewhere and the fields are returned by the main component.
const EditView = ({permission}) => {
const [editable, setEditable] = useState();
const [values, setValues] = useState([]);
useEffect(() => {
setEditable(permission);
}, [permission]);
useEffect(() => {
//maybe fetch your data from a back end or whatever and assign it to `values`
//on page load
}, [])
const ExampleField = ({permission, val, index}) => {
const handleChange = (e) => {
let vals = [...values];
vals[index] = val;
setValues(vals);
}
return(
<>
{permission
? <input name="example" type="text" defaultValue={val}
onChange={handleChange} />
: <span>{val}</span>}
</>
)
}
const fields = values.map((value, i) => {
return <ExampleField permission={permission} val={value} index={i}/>
})
return(
<>
{fields}
</>
)
}
Most likely, you'll want to break out various field components into their own file and, instead of using useState, you would probably want to explore useContext or useStore type functionality to lift up your state and do all the react things.
*Haven't tested or even compiled this code - for illustration purposes only.

I am displaying dynamic data on this React Boostrap Slider. Is there a way to make the code more efficient?

this is my first post here. I am building a React Boostrap Carousel that pulls Movie data from the database and displays it. I am new to React and programming in general. So far i made the code work. But i do not know how to handle the images. The images are stores in React **src/assets/imgs. **. Should i store a reference to the image in the database like so ../../assets/imgs/the-batman.jpg and then display it? If so later on on the project the admin will have to create a MovieOfTheMonth. He should be able to input movie title, descrition etc, and also upload a movie image. Is there a way when the image is uploaded it, to store it to a specific folder, in this case src/assets/imgs and also create a reference in the database? I do not need the solution here, just to tell me if it is achievable. Finally is there a way to improve my code?
this is my full code for this component
import React, {useState, useEffect } from 'react';
import './Carousel.css'
import Carousel from 'react-bootstrap/Carousel';
import 'bootstrap/dist/css/bootstrap.min.css';
import axios from 'axios';
const CarouselHero = () => {
//boostrap code
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
//Get Movies of the month
const [movie, setMovie] = useState([])
const getMovie = () => {
axios.get("http://localhost:4000/moviesOfTheMonth")
.then((res) => {
const myMovie = res.data
myMovie.push()
setMovie(myMovie);
})
}
useEffect(() => getMovie(), []);
return (
<Carousel activeIndex={index} onSelect={handleSelect} fade>
{movie.map((item) => {
const {id, title, description} = item.Movie
return (
<Carousel.Item interval={2000}>
<img
src={require("../../assets/imgs/the-batman.jpg")}
alt="First slide"
/>
<Carousel.Caption >
<h1>{title}</h1>
<p>{description}</p>
<button>Book Now</button>
</Carousel.Caption>
</Carousel.Item>
)
})}
</Carousel>
);
};
export default CarouselHero;
I think technically it is achievable to iterate over the assets folder and create database entries for new images (create and compare hash?), but it is usually not how you do it. I would put images in some file storage like S3 and reference them with id.
I don't know who the admin will be in your project, but if admin is rather a non technical person, you could create (or use a template of course) a small and simple admin dashboard, where he/she can maintain a movie of the month via UI.
FFinally some remarks on your code:
const handleSelect = (selectedIndex, e) => { setIndex(selectedIndex); }; - If you need only first, but not second, third etc. argument, you can just leave it out: (selectedIndex) => ...
const [movie, setMovie] = useState([]) - don't forget to use semicolon after every statement. (They are optional, but are useful sometimes to avoid weird errors). Also, you have a list here. So maybe better call it "movies".
myMovie.push() - What are you trying to push here?
useEffect(() => getMovie(), []); - Usually you define and call async function directly in useEffect. Don't you get any hints or warning?
movie.map((item) => { - When you iterate and get a list back React needs a key on every element (here on Carousel.Item). Don't just use the index, as it is a bad practice. Always try to find id property in your data.
const {id, title, description} = item.Movie - Why is the data nested by Movie object? Can't you just say item.id, item.title, item.description?

In React application, Images cannot show when an image url is string property of a object

I cannot show the image when the image url is string property in a object.
For example:
import React, {Fragment, useState} from 'react';
const profile = (props) => {
const [user, setUser] = useState(null);
useEffect(() => {
setUser({
name: 'John',
photo: './asset/images/user.png'
})
}, [])
return (
<Fragment>
<img src={user.photo} alt="photo" />
<p>{user.name}</p>
</Fragment>
)
}
Of course I can solve this by importing image object like import img from './assets/images/user.png'. But I need to know how to show image without importing it.
Does anyone solve the problem?
You can see one example working here: https://codesandbox.io/s/relaxed-sinoussi-ikown?file=/src/App.js
The main problem is you're trying to access the image as a relative route from your component.
But, when you want to do something like that your component can be anywhere in the application. So, the way to do it is:
Include your images in public/
Access your images using the absolute route from /public

How to render an element in React which was created by createElement()?

I have created an image element by using:
const image = document.createElement('image'); // or new Image();
How can I render this image variable in React ?
I don't want to use Html tags to do something like this:
<img src={image.src} ... />
Is there any other way ?
Well either create a <div class="parent"> </div> and then use
document.querySelector(".parent").appendChild(imageElement)
or simply,
document.appendChild(imageElement)
This is the wrong way to go about doing this. You shouldn't directly manipulate the DOM with React. I would instead have an array of objects in your state, and in your component, map the objects to the elements of your choosing. Like this
const Component = () => {
const [components, setComponents] = useState([{src:'path/to/src', alt:'altTag'}])
return(
<>
{
components.map(e => {
return(<img src={require(e.src)} alt={e.alt} />)
})
}
</>
)
}
Wrote this from memory/without testing so there might be something wrong so dont kill me. But if you need to render it anywhere, make it its own component. If it's truly just one image, then you don't need the array/map just use an object and render it same way

Is it possible to copy an object's properties from one component and display them in another component using refs?

Say I have 2 components. One is a table with a list of stores. Each store has properties like color, item, open, closed. The other component is one to create a store.
I want to be able to click on a little copy icon on one of the created stores already, and take that information to the create store component, and populate that component with the properties in order to make changes and create a completely new store.
Is this doable using refs? Or is there a better way of doing this?
Use ref to this task is a mistake. React works using a Virtual DOM that is a cleaner and faster Object Tree with information that will be through to DOM by React DOM the REF API is used to access direct the DOM information, and you don't need any information from DOM to do ur task.
https://reactjs.org/docs/refs-and-the-dom.html
A way yo do what you describe is create a state/setState on the parent component and pass a state for the store component and a setState to the table component for example:
import React, { useState } from 'react'
const StoreComponenet = ({ color, item, open})=>{
// logic of component
return (
<div>
// ...
</div>
)
}
const TableComponent = ({ setStore })=>{
// logic of component
return (
<table>
<tr onClick={() => setStore("blue", {id: 2, name: "BlueStore" }, false)}>
Build blue store
</tr>
...
</table>
)
}
const App = ()=>{
const [store, setStore] = useState(null)
return (
<TableComponent setStore={setStore} />
{
store &&
<StoreComponent
color={store?.color}
item={store?.item}
open={store?.open}
/>
}
)
}