React Native Image Binding - javascript

Trying to navigate some React Native image bindings which I am unsure how to proceed.
Right now, the following code works.
I have a data file of items:
MyData.js
import { Images } from '#configuration';
const myData = [
{
name: 'One',
img: Images.one
},
{
name: 'Two',
img: Images.two
},
{
name: 'Three',
img: Images.three
}
]
And the images.js file
export const Images = {
one: require('#assets/images/one.png'),
two: require('#assets/images/two.png'),
three: require('#assets/images/three.png')
}
And in my React screen, I am trying to render that as:
import {MyData} from '#data';
export default function MyScreen({navigation}) {
const [myData] = useState(MyData);
return (
<View>
<FlatList data={myData} keyExtractor={(item, index) => item.name}
renderItem={({item, index}) => (
<Card image={item.img}>
</Card>
)}
</>
</View>
)
}
The above displays the image accordingly.
Now, I wanted to have the data binding of the FlatList bound to an API which returns the following JSON:
[
{
name: "One",
img: "Images.one"
},
{
name: "Two",
img: "Images.two"
},
{
name: "Three",
img: "Images.three"
}
]
Of course the binding to the Card image does not work as the img is interpreted as a string.
I tried to modify the image binding to:
<Card image={JSON.parse(item.img)}>
</Card>
But this simply throw an error and the image does not render.
Simply stumped on how images would be handled in this scenario.
Any insight would be appreciated. Thanks.

If you can do some adjustment in your json, it is possible
Just keep image name inside json data
{
name: "One",
img: "one"
},
{
name: "Two",
img: "two"
},
{
name: "Three",
img: "three"
}
]
and when you want to render it you can use
import { Images } from '#configuration';
<Card image={Images[item.img]}>
</Card>

If your name property is always same as the actual image source, then I would consider using name property to extract image url like below:
import { Images } from '#configuration';
<Card image={Images[item.name.toLowerCase()]}>
</Card>

Related

Working with state on recursive components

I'm writing a component that renders itself inside recursively and is data-driven
Attaching my sandbox snippet, as it will be easier to see there.
This is my data:
var builderStructureData = [
{
id: 123,
value: 3,
children: []
},
{
id: 345,
value: 5,
children: [
{
id: 4123,
value: 34,
children: [
{
id: 342342,
value: 33,
children: []
}
]
},
{
id: 340235,
value: 3431,
children: [
{
id: 342231342,
value: 3415,
children: []
}
]
}
]
}
];
and it renders like this:
This is my App.js:
import { useState } from "react";
import "./App.css";
import Group from "./components/group";
import builderStructureData from "./components/builderStructureData";
function App() {
const [builderStructure, setBuilderStructure] = useState(
builderStructureData
);
return (
<div className="App">
{builderStructure.map((x) => {
return <Group key={x.id} children={x.children} value={x.value} />;
})}
</div>
);
}
export default App;
And this is my recursive component:
import React from "react";
export default function Group(props) {
let childrenArray = [];
if (props.children) {
props.children.map((x) => childrenArray.push(x));
}
return (
<div className="group" draggable>
<p>this is value: </p>
<input value={props.value} readOnly={true}></input>
<button>Add Group</button>
{childrenArray.map((x) => {
return <Group key={x.id} children={x.children} value={x.value} />;
})}
</div>
);
}
I can render the components based on the data, and it seems to be handling recursion fine. I need to store the state on the App.js page and be able to change it from within child components. For example, if I update the "value" field of the component with ID = 342342, I want it to update that corresponding object in the state no matter how deeply nested it is, but not sure how to do that as it is not as simple as just passing a prop.
Am I taking the right approach with my code snippet? How can I do the state update?
I would advise the state normalization approach - here is an example for redux state - https://redux.js.org/usage/structuring-reducers/normalizing-state-shape - but you can use this approach with your state. So - your state will look like this:
state = {
items: {
[123]: {
id: 123,
value: 3,
childrenIds: []
},
[345]: {
id: 345,
value: 5,
childrenIds: [4123, 340235]
},
[4123]: {
id: 4123,
value: 34,
parentId: 345,
childrenIds: [342342]
},
[342342]: {
id: 342342,
value: 33,
parentId: 4123,
childrenIds: []
},
[340235]: {
id: 340235,
value: 3431,
parentId: 345,
childrenIds: [342231342]
},
[342231342]: {
id: 342231342,
value: 3415,
parentId: 340235
childrenIds: []
}
}
}
Here the field "childrenIds" is an optional denormalization for ease of use, if you want - you can do without this field. With this approach, there will be no problem updating the state.
You are thinking this in a wrong way, it should be very easy to do what you want.
The most imported thing is to make a little small changes in Group
Please have a look
import React from "react";
export default function Group(props) {
const [item, setItem] = React.useState(props.item);
let childrenArray = [];
if (item.children) {
item.children.map((x) => childrenArray.push(x));
}
const updateValue = ()=> {
// this will update the value of the current object
// no matter how deep its recrusive is and the update will also happen in APP.js
// now you should also use datacontext in app.js togather with state if you want to
// trigger somethings in app.js
item.value =props.item.value= 15254525;
setState({...item}) // update the state now
}
return (
<div className="group" draggable>
<p>this is value: </p>
<input value={item.value} readOnly={true}></input>
<button>Add Group</button>
{childrenArray.map((x) => {
return <Group item={x} />;
})}
</div>
);
}
The code above should make you understand how easy it is to think about this as an object instead of keys.
Hop this should make it easy for you to understand

problem while importing dynamic images to url in react

I am making a react project, where I want to import the set of images from a data.tsx file such that it should set inside the backgroundImage url of the element in which the 'data' is mapped into.
But, my images are not visible as the background image of the element, also I am not getting any kind of error message from the compiler instead. My code is as follows -
import start from "../assets/Board/hut.png";
import image2 from "../assets/Board/Man.png";
import image3 from "../assets/Board/Factory.png"
const Tiles = [
{
id: 1,
name: "start",
bgImage : `url(${start})`
},
{
id: 2,
name: "two",
bgImage : `url(${image2})`
},
{
id: 3,
name: "three",
bgImage : `url(${image3})`
}];
and now I am using it into my component as
import Tiles from "../../Data/tileData";
export default function Dashboard(){
return(
<>
<Grid container>
{Tiles.map((tile) => (
<Grid item xs={1} key={tile.id}>
<Paper elevation ={2} sx={{backgroundImage : `url(${tile.bgImage})` }}
</Grid>
))}
</Grid>
</>
)
}
I have tried almost every workAround this, but didn't get any concrete results. None of my method is mapping the background Image of the Paper element dynamically.
Methods I tried -
A.) By moving the images into the Public Folder and then setting it as the backgroundImage inside my component file's sx ={{}} attribute.
B.) By using my backgroundImage as
sx={{backgroundImage : tile.bgImage }}
C. ) By refactoring my orignal object array as -
const Tiles = [
{
id : 1,
name : "start",
bgImage : "/Board/hut.png" //after adding the Board folder inside Public folder.
}, {...}, {...}}];
and then passing the backgroundImage as
sx={{ backgroundImage : `url(${tile.bgImge})`}}
I have also refactored my data file as this -
const Tiles = [
{
id: 1,
name: "start",
bgImage : '/Board/hut.png'
},
{
id: 2,
name: "two",
bgImage : '/Board/Man.png'
},
{
id: 3,
name: "three",
bgImage : '/Board/Factory.png'
}];
//note - all the references to the images are now from inside the public folder instead.
but, it doesn't work instead
none of the above mentioned methods worked for me.
I want to set the 'backgroundImage' of the element mapping my 'object array' , is there any specific work around this?
suggestions are honoured
If you are using this import images in Object. That is going to treat as an object inside of Image tag (). try to import images on the Image tag and assign them.
import start from "../assets/Board/hut.png";
import image2 from "../assets/Board/Man.png";
import image3 from "../assets/Board/Factory.png"
const Tiles = [
{
id: 1,
name: "start",
bgImage : `url(${start})`
},
{
id: 2,
name: "two",
bgImage : `url(${image2})`
},
{
id: 3,
name: "three",
bgImage : `url(${image3})`
}];
Do this in array:
{
id: 1,
name: "one",
}
Better to define the name with id. and access from the same page. like this
import hut1 from "../assets/Board/hut.png";
import image2 from "../assets/Board/Man.png";
sx={{ backgroundImage : hut1}}
sx={{ backgroundImage : image2}}
For now, as per my experience, it's work.
One thing more, you can add image URL link in this that works too.
{
id: 1,
name: "start",
bgImage : 'https://picsum.photos/200'
}
But Definitely, I will share any other option if I got.

Getting content of currently active Text component wrapped inside popover of antd

I am using antd components for my react app. I have a Text component wrapped inside of Popover component. Now in my case this Popover is applied to one particular column of table, i.e. every row-element in that column has a Popover component rendered for it upon mouse hovering.
title: "Name",
dataIndex: "name",
key: "name-key",
sortType: "string",
sortDirections: ["descend", "ascend"],
sorter: (a, b) => a.name.length - b.name.length,
render: (text, record) => (
<Popover>
<Text onMouseOver={handleOnMouseOverCommitId}> {name} </Text>
</Popover>
)
I want to get hold of the row-element's value, the one contained by the above Text component whenever I hover over it. In this case the value denoted by {name} above.
I tried getting it with e.target.value via onMouseOver event, but it returned undefined.
I think I get the reason behind it, because the event.target returns an html node of type <span>.
With a normal div element e.target.value has worked in the past for me. But doing the same thing with a predefined component like antd's Text seems a bit trickier.
Just to elaborate, the Popover has two buttons and based on which button user clicks, I need to render some other components, something like an overlay component.
But in order to do that I would also need to get hold of the text value which originally triggered the Popover.
Below is the code(most of the things removed for preciseness).
record.name is what I ultimately need to capture.
<Popover
content={
<>
<Space>
<Button onClick={showSomeOverlayPaneForName}>
{"View Details for record.name"}
</Button>
<Button href={"https://abc.xyz.com/" + record.role}>
{"View Role Details"}
</Button>
</Space>
</>
}
trigger={"hover"}
>
<Text style={{"color": blue.primary}} copyable={true} onMouseOver={handleOnMouseOverName}>{record.name}</Text>
</Popover>
The handleOnMouseOverName function(which doesn't work anyway) :
const handleOnMouseOverName = (e) => {
//console.log("e.target.value :--- ", e.target.value);
setCurrentActiveName(e.target.value)
}
And once my currentActiveName variable is set(via useState), I use that value inside my function showSomeOverlayPaneForName
const showSomeOverlayPaneForName = (e) => {
axios
.get(
`some-url`,
{
params: {name: currentActiveName}
}
)
.then((response) => {
setData(response.data);
}).catch(reason => {
//xyz
});
}
You need to pass on the record of the enclosing render function to the handleOnMouseOverName function.
Check the following example
import React from 'react';
import 'antd/dist/antd.css';
import './index.css';
import { Space, Table, Button, Popover } from 'antd';
const App = () => {
const data = [
{
key: '1',
name: 'John Brown',
address: 'New York No. 1 Lake Park',
role: 'admin',
},
{
key: '2',
name: 'Jim Green',
address: 'London No. 1 Lake Park',
role: 'user',
},
{
key: '3',
name: 'Joe Black',
address: 'Sidney No. 1 Lake Park',
role: 'manager',
},
];
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
render: (name, record) => {
const content = (
<>
<Space>
<Button
onClick={() => {
viewDetail(record);
}}
>
{'View Details for ' + record.name}
</Button>
<Button href={'https://abc.xyz.com/' + record.role}>
{'View Role Details'}
</Button>
</Space>
</>
);
return (
<>
<Popover content={content} title="Details">
<div
onMouseOver={() => {
handleOnMouseOverName(record);
}}
>
{name}
</div>
</Popover>
</>
);
},
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
},
];
const handleOnMouseOverName = (record) => {
console.log(record);
};
const viewDetail = (record) => {
console.log(record);
};
return <Table columns={columns} dataSource={data} />;
};
export default App;
Output:
I hope this helps.
From antd docs: https://ant.design/components/popover/#header
Apparently you're supposed to render the <Popover/> with a content={content}-prop
For example
const content = <div>Content to render under title</div>
const App = () => {
const value = "Text to hover";
return (
<Popover content={content} title="Title">
<Text>{value}</Text>
</Popover>
)
}

Image will not load when trying to call it up from from local JSON file

I was able to bring in data dynamically from a local JSON file I created in RN. However, when I went back and inserted an image for each profile so that it can be displayed dynamically with their profile info, the app broke saying "The component cannot contain children. If you want to render content on top of the image, consider using ".
I am using a background for all of the profiles already, so I really don't understand what it is saying, since the images I inputted in the JSON file would be a profile image for each character. Am I even following the proper format to call up an image? Any help would be appreciated.
This is how I have my JSON File set up:
const characters = [
{ id: "1", name: "Homer Simpson", occupation: "Nuclear Safety Inspector",
url:
"https://assets.fxnetworks.com/cms/prod/shows/the-simpsons/photos/simpsons-sidebar/character-facts/Homer/swsb_character_fact_homer_288x763.png"
},
{ id: "2", name: "Marge Simpson", occupation: "Stay-at-home mom", url:
"https://assets.fxnetworks.com/cms/prod/shows/the-simpsons/photos/simpsons-sidebar/character-facts/Homer/swsb_character_fact_homer_288x763.png"},
{ id: "3", name: "Bart Simpson", occupation: "Student", url:
"https://assets.fxnetworks.com/cms/prod/shows/the-simpsons/photos/simpsons-sidebar/character-facts/Homer/swsb_character_fact_homer_288x763.png" },
{ id: "4", name: "Lisa Simpson", occupation: "Student", url:
"https://assets.fxnetworks.com/cms/prod/shows/the-simpsons/photos/simpsons-sidebar/character-facts/Homer/swsb_character_fact_homer_288x763.png" },
{ id: "5", name: "Maggie Simpson", occupation: "Baby", url:
"https://assets.fxnetworks.com/cms/prod/shows/the-simpsons/photos/simpsons-sidebar/character-facts/Homer/swsb_character_fact_homer_288x763.png" }
export default characters;
This is how I am bringing it in:
import React from "react";
import {
View,
Text,
StyleSheet,
Image,
Button,
ImageBackground
} from "react-native";
class CharacterProfiles extends React.Component {
static navigationOptions = {
title: "The Simpsons",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: {
fontWeight: "bold"
}
};
render() {
const { item } = this.props.navigation.state.params;
return (
<View>
<ImageBackground
source={{
uri:
"https://backgrounddownload.com/wp-content/uploads/2018/09/simpsons-clouds-background-5.jpg"
}}
style={{ width: "100%", height: "100%" }}
>
<Image>{item.url}</Image>
<Text>Name: {item.name}</Text>
<Text>Occupation: {item.occupation}</Text>
<Button
title="Character Directory"
onPress={() => this.props.navigation.navigate("CharacterDirectory")}
/>
<Button
title="Homepage"
onPress={() => this.props.navigation.navigate("Home")}
/>
</ImageBackground>
</View>
);
}
}
export default CharacterProfiles;
In the same way as you've already done with your ImageBackground component, you need to use the source attribute to assign the URL of an Image. You can see examples of this in more detail in React Native's Image component documentation.
<Image
source={{uri: item.url}}
/>
Including the source URL in the content of the <Image> tag as text will have no effect. Doing this would essentially be equivalent to writing the following in HTML:
<img>https://example.com/myImage.png</img>
You're getting the warning about placing content on top of the image because React Native thinks you're trying to superimpose the URL as text on the image. Since HTML <img> elements can't do this, neither can the Image component.

How to create a nested menu in JavaScript?

So I want to achieve the image below but with content sent from server.
We can set menu items
const items = [
{ key: 'editorials', active: true, name: 'Editorials' },
{ key: 'review', name: 'Reviews' },
{ key: 'events', name: 'Upcoming Events' },
]
//...
<Menu vertical color='black' items={items}>
</Menu>
However, I do not see how to nest them. Just setting item 'content' to some XML.
How do I create a menu with multiple nested sections in ReactJS\Semantic-UI in Javacript?
I would create the following components:
<MenuContainer /> -> our root component
<Menu></Menu> -> can render either itself (<Menu />) or an <Item /> component
<Item></Item> -> can render only a <li /> or smth
And suppose we have the following JSON coming from our server:
{
label: 'Some menu',
children: [{ label: 'Sub menu', children: [...] }, ...],
}
Let assume that when we find an array in our JSON, that means that we have to render a menu. If we have an object, we render a simple child. A rough algorithm would be:
const MenuContainer = ({items}) => ({
{items.map(item => item.items ? <Menu items={items} /> : <Item data={item} /> }
});
Is this something you are looking for?

Categories

Resources