Is it possible to pass variable to antD Statistics component in React? - javascript

I'm trying to render data from a variable / function into an antD Statistic Component. It appears it can only take a raw string or number, but I need to pass data from props into it.
Is there a way around this? See code below - I would like to pass scenarios[0].investment into "Statistic title="Investment" value={scenarios[0].investment}" but it doesn't allow it. Current code below works AS-IS but breaks when I replace it with scenarios[0].investment
class RenderSummary extends Component {
state = {
clicked: false,
hovered: false,
};
hide = () => {
this.setState({
clicked: false,
hovered: false,
});
};
handleHoverChange = visible => {
this.setState({
hovered: visible,
clicked: false,
});
};
handleClickChange = visible => {
this.setState({
clicked: visible,
hovered: false,
});
};
render() {
const scenarios = this.props.scenarios;
const data = [
{
title: 'Title 1', content: <Statistic title="Investment" value={0}/>,
},
{
title: 'Title 2', content: <Statistic title="T Savings" value={0}/>,
},
{
title: 'Title 2', content: <Statistic title="E Savings" value={0}/>,
},
];
const hoverContent = <div>This is hover content.</div>;
const clickContent = <div>This is click content.</div>;
const onClick = () => console.log("Works!");
return(
<div className="container">
<div className="site-card-wrapper">
<Row gutter={16}>
<Col span={12}>
<Card title="User Scenario 1" bordered={true}>
<List
grid={{ gutter: 16, column: 3 }}
dataSource={data}
renderItem={item => (
<List.Item>
{item.content}
</List.Item>
)}
/>
</Card>
</Col>
</Row>
</div>
</div>
);
}
}
scenarios in props as follows
"scenarios : [0: {id: 0, investment: 0, tSavings: 0, eSavings: 0 …},1: {id: 0, investment: 1, tSavings: 1, eSavings: 1 …}]"

I think the way you have structured your scenarios array or the way you are passing it is incorrect.
An example of how you could pass scenarios to RenderSummary:
const App = () => {
const scenarios = [
{investment: 1}, // Add your other properties
{investment: 2},
{investment: 3},
]
return <RenderSummary scenarios={scenarios}/>
}
If you pass scenarios like above, you can pass it in the way you wanted to:
const data = [
{
title: "Title 1",
content: <Statistic title="Investment" value={scenarios[0].investment} />,
},
{
title: "Title 2",
content: <Statistic title="T Savings" value={scenarios[1].investment} />,
},
{
title: "Title 2",
content: <Statistic title="E Savings" value={scenarios[2].investment} />,
},
];

Related

How to add a className to a reactjs component that is inside an array?

I have an array that contains objects containing icon component and titles like this :
const skills = [
{ icon: <FaHtml5 className="skill-icon" />, title: "HTML5" },
{ icon: <FaCss3 className="skill-icon" />, title: "CSS3" },
{ icon: <SiJavascript className="skill-icon" />, title: "JavaScript" },
{ icon: <FaReact className="skill-icon" />, title: "ReactJS" },
{ icon: <SiBootstrap className="skill-icon" />, title: "Bootstrap" },
];
I have to write className="skill-icon" to every component... I tried this way of adding className but this didn't work:
skills.map((add_class) => {
add_class.icon.add.classList("myClass");
console.log(add_class);
});
Should we have to write className='skill-icon' inside that array like I'm doing or is there any other way to iterate over all the component and add className ?
My HTML looks like this :
<section className="skill-card-section">
{skills.map((skill) => {
//iterating over all the skills from that skills array
return (
<section className="skill-card" key={skill.title}>
{skill.icon}
<p className="skill-title">{skill.title}</p>
</section>
);
})}
</section>
Instead of creating a React.Node (by calling <Component/> which is a synthetic sugar for React.createElement) in your skills array, you can assign the component itself.
const skills = [
{ iconComponent: FaHtml5, title: "HTML5" },
{ iconComponent: FaCss3, title: "CSS3" },
{ iconComponent: SiJavascript, title: "JavaScript" },
{ iconComponent: FaReact, title: "ReactJS" },
{ iconComponent: SiBootstrap, title: "Bootstrap" },
];
<section className="skill-card-section">
{skills.map((skill) => {
const Component = skill.iconComponent;
return (
<section className="skill-card" key={skill.title}>
<Component className="skill-icon" />
<p className="skill-title">{skill.title}</p>
</section>
);
})}
</section>;

Select value doesnt change the first time I trigger onChange event when using setSate React

I have a set of select menus and I am trying to change a value when I select an option using onChange={updateValue} event. When I first select an option, the value is not being updated in the select menu.
It only changes the second time I try to choose an option. Not sure what I am doing wrong.
Edit: I did some more research (OnChange event using React JS for drop down) and I believe I need the value of the select to be updated as well, using setState. I cant figure out how to do it without having a variable for each value and set the state again.
let selectMenus = [
{
id: 'id1',
name: 'name1',
label: 'label1',
value: '0',
options: [
{
text: 'All ages',
value: '0',
},
{
text: '35 - 37 yrs',
value: '1',
},
],
buttonLabel: 'Refresh',
},
{
id: 'id2',
name: 'name2',
label: 'label2',
value: '1',
options: [
{
text: 'All ages',
value: '0',
},
{
text: '45 - 50 yrs',
value: '1',
},
],
buttonLabel: 'Refresh',
},
];
const [url, setUrl] = useState('http://localhost:5000/selectDropdowns1');
const updateValue = () => {
setUrl('http://localhost:5000/selectDropdowns2');
};
<form>
{selectMenus.map((select) => (
<div key={select.id} className='select-container'>
<label htmlFor={select.id}>{select.label}</label>
<select id={select.id} name={select.name} value={select.value} onChange={updateValue}>
{select.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{select.buttonLabel}</button>
</div>
))}
</form>;
The problem is that when you provide onChange prop to select component it become a controlled component.
For more information: React Docs - Forms #controlled components
When you dealing with controlled components you must provide a value to it and when onChange triggerd it should update that value to work properly. Since you did not provide the full code, I imagine you have an array of select menus and options attached to it.
So in this case every select component should have own onChange method and own value to work properly. To achive this we should create another component for only Select Options. Like this;
function SelectComponent({ optionList, onSelected }) {
const [value, setValue] = useState();
const updateValue = ({ target }) => {
setValue(target.value);
if (onSelected) onSelected(target.value);
};
return (
<>
<label htmlFor={optionList.id}>{optionList.label}</label>
<select
id={optionList.id}
name={optionList.name}
value={value}
onChange={updateValue}
>
{optionList.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{optionList.buttonLabel}</button>
</>
);
}
This component accepts to props; optionList and onSelected
optionList is the list of options to render
onSelected is a method that we call when user select and option
On main component, we should change the select section with our select component with props optionList and onSelected
return (
<div>
{selectMenus.map((select) => (
<div key={select.id} className="select-container">
<SelectComponent optionList={select} onSelected={updateValue} />
</div>
))}
</div>
);
So overall code is like this:
import { useState } from "react";
import { v4 as uuid } from "uuid";
export default function App() {
const [url, setUrl] = useState();
const updateValue = (value) => {
setUrl(value);
};
const selectMenus = [
{
id: 1,
label: "Menu 1",
name: "menu1",
buttonLabel: "Menu 1",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
},
{
id: 2,
label: "Menu 2",
name: "menu2",
buttonLabel: "Menu 2",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
},
{
id: 3,
label: "Menu 3",
name: "menu3",
buttonLabel: "Menu 3",
options: [
{
text: "option 1",
value: "option1"
},
{
text: "option 2",
value: "option2"
},
{
text: "option 3",
value: "option3"
}
]
}
];
return (
<div className="App">
<h1>URL Value: {url}</h1>
{selectMenus.map((select) => (
<div key={select.id} className="select-container">
<SelectComponent optionList={select} onSelected={updateValue} />
</div>
))}
</div>
);
}
function SelectComponent({ optionList, onSelected }) {
const [value, setValue] = useState();
const updateValue = ({ target }) => {
setValue(target.value);
if (onSelected) onSelected(target.value);
};
return (
<>
<label htmlFor={optionList.id}>{optionList.label}</label>
<select
id={optionList.id}
name={optionList.name}
value={value}
onChange={updateValue}
>
{optionList.options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
<button>{optionList.buttonLabel}</button>
</>
);
}
Working example is overhere codesandbox

Updating State Through props with hooks

I am trying to update the state of something on a click from a component by lifting up the state and passing it as a prop into the other component and trying to update it.
this is the App.js
function App() {
const [currentConfig, setCurrentConfig] = useState(0);
const availableConfigs = [
{ id: 1, name: "Config 1", number: 1, key: 1 },
{ id: 2, name: "Config 2", number: 2, key: 2 },
{ id: 3, name: "Config 3", key: 3 },
{ id: 4, name: "Config 4", key: 4 },
{ id: 5, name: "Config 5", key: 5 },
{ id: 6, name: "Config 6", key: 6 },
{ id: 7, name: "Config 7", key: 7 },
];
const [configs, setConfigs] = useState(availableConfigs);
//function undoConfigAnimation(currentConfig) {}
return (
<div>
<Tree
configs={configs}
animateConfigs={startConfigAnimation}
setConfig={setCurrentConfig}
currentConfig={currentConfig}
/>
<NavBar />
</div>
);
function startConfigAnimation(configClicked) {
console.log(currentConfig);
configs.forEach((config) => {
if (configClicked !== config.name) {
var elm = document.getElementById(config.name);
elm.style.transform = "translate(-200px)";
setTimeout(() => (elm.style.transform = "rotateZ(180deg)"), 1000);
}
});
}
}
export default App;
this is the component
function Tree(props) {
return (
<div class="treeContainer">
{props.configs.map((config) => {
return (
<div
id={config.name}
class="container1"
onClick={() => {
props.setConfig(config.name);
props.animateConfigs(config.name);
if (props.currentConfig !== config.name) {
props.setConfig.bind(config.name);
}
}}
>
<Configs configNumber={config.number} configName={config.name} />
</div>
);
})}
</div>
);
}
export default Tree;
currently, it does update the state, but it only updates it to the state before the click so an example output if the currentConfig === 0 would be as follows
click config 1
currentConfig = 0
click config 2
currentConfig = "config 1"
Since the setState is async, the console.log will always be one behind. This does not mean that the state is not updated, but only not displayed in the console or yet available in the function.
So the flow would be:
You dispatch the change.
You call startConfigAnimation, but it is still in sync, so that currentConfig is still the previous value.
The state is updated with the new value.
There are 2 ways to fix this:
Use a useEffect:
Listen to the currentConfig with a useEffect and trigger the animation, if the config changes.
React.useEffect(() => startConfigAnimation(currentConfig), [currentConfig])
You are already passing the new/updated config to startConfigAnimation so you could be using that.

react native videos in carousel

I have been trying to play single video from a slider containing of multiple videos and images..
What i used and tried is in below.
1. react-native-video, 2. react-native-snap-carousel
How to pause and play the videos wrapped in horizontal carousel and also which are in vertical FlatList Feeds
This is my carousel :
<View style={styles.sliderImgView}>
<Carousel
ref={(c) => { this._carousel = c; }}
data={chordData.images}
firstItem={0}
autoplay={autoPlay}
layout={layout}
loop={loop}
renderItem={this._renderItem}
onSnapToItem={(ind) => this.setState({ activeSlide: ind })}
loopClonesPerSide={bannersDataLength}
sliderWidth={SCREEN_WIDTH}
itemWidth={SCREEN_WIDTH} />
</View>
And my _renderItem is here :
if (item.mediaType === "image") {
return (
<View style={[styles.sliderImgView, GlobalStyles.ajCenter]} key={index}>
<Image source={{ uri: item.imgUrl }} resizeMode={"cover"} style={[styles.sliderImageStyle]} />
</View>
)
} else {
return (
<View style={[styles.sliderImgView, GlobalStyles.ajCenter]} key={index}>
<Video
source={{ uri: item.imgUrl }} // Can be a URL or a local file.
ref={(ref) => { this.player = ref }} // Store reference
resizeMode={"cover"}
paused={index !== this.state.activeSlide}
onLoad={this.onVideoLoad}
onError={this.onVideoError}
controls={false}
style={styles.backgroundVideo} />
</View>
)
}
And my Array look's like this :
result: [
{
id: 1,
title: "Feed Title",
description: "Feed description....",
data: [
{
id: 1,
mediaType: "image",
imgUrl: "https://images.unsplash.com/photo-1473177027534-53d906e9abcf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1049&q=80"
},
{
id: 2,
mediaType: "video",
imgUrl: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
},
{
id: 3,
mediaType: "image",
imgUrl: "https://images.unsplash.com/photo-1473177027534-53d906e9abcf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1049&q=80"
},
{
id: 4,
mediaType: "video",
imgUrl: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
},
]
},
{
id: 2,
title: "Feed Title",
description: "Feed description....",
data: [
{
id: 1,
mediaType: "image",
imgUrl: "https://images.unsplash.com/photo-1587269012604-b20cfbca7b16?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=849&q=80"
}
]
},
{
id: 3,
title: "Feed Title",
description: "Feed description....",
data: [
{
id: 1,
mediaType: "image",
imgUrl: "https://images.unsplash.com/photo-1473177027534-53d906e9abcf?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1049&q=80"
},
{
id: 2,
mediaType: "video",
imgUrl: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
},
]
},
{
id: 4,
title: "Feed Title",
description: "Feed description....",
data: [
{
id: 1,
mediaType: "image",
imgUrl: "https://images.unsplash.com/photo-1584679109597-c656b19974c9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80"
}
]
}
]
I don't want to show the player control that's why i hide it.. just like Instagram.
I don't know whether i should use this or not.
Present issue is: i should only play the video which is in visible section of user eyes which is in FlatList (i had't mention my flatList code as it is just list_design). i had scroll list with multiple objects with media data in arrays. how can i manage to stop playing id number 1 object of data array with id 2 or 4 active video index when other id number 3's media is in active.
I just want to achieve same as like Instagram post with no performance lagging issues.
can anyone please suggest or help me to achieve this.
Below did the magic controlling other feed's post media sliders to pause the video.
Add the below two props to your FlatList to get the current visible Index., and when ever the current visible index value changes update in componentDidUpdate and call your videoLoad method.
viewabilityConfig={{viewAreaCoveragePercentThreshold: 200}}
onViewableItemsChanged={this.onViewableItemsChanged}
onViewableItemsChanged = ({ viewableItems, changed }) => {
if (viewableItems && viewableItems.length > 0) {
this.setState({ currentVisibleIndex: viewableItems[0].index });
}
}
componentDidUpdate(prevProps, prevState){
if (prevProps.currentVisibleIndex !== this.props.currentVisibleIndex) {
this.setState({ currentVisibleIndex: this.props.currentVisibleIndex }, () => {
this.onVideoLoad();
})
//console.log("Check prevProps: " + prevProps.currentVisibleIndex + "----> Check pevState: " + prevState.currentVisibleIndex);
}
}
The best way to achieve this is using inviewport
For the above answer viewabilityConfig and onViewableItemsChanged
These props works for flatlist but react-native-snap-carousel the props (viewabilityConfig and onViewableItemsChanged) are not supported
As name of library suggest it might be only supported to images not video since it renders multiple time for loop

How to setState on Object item within array

I want to update state of key heart in the array's objects when the heart icon pressed it changes to red so for this I'm using react native icons and i'm using heart and hearto to switch when click on it
here is the code:
state = {
localAdversiment: [
{
title: "Ecloninear 871",
image: require("../../assets/images/truck_image.png"),
year: "2015",
type: "Truck",
status: "new",
price: "$ 2000",
heart: "hearto"
}
Here it function which is called when heart icon pressed
handleFavourite = index => {
const { heart } = this.state.localAdversiment[index];
this.setState(
{
heart: "heart"
}
);
};
here is the heart icon code
<TouchableOpacity onPress={() => this.handleFavourite(index)}>
<Icon
name={item.heart}
type={"AntDesign"}
style={{ fontSize: 18 }}
/>
</TouchableOpacity>
kindly help me how to update heart as heart instead of hearto when clicked
You can do it easily by following approach
state = {
localAdversiment: [
{
id: 0,
title: "Ecloninear 871",
image: require("../../assets/images/truck_image.png"),
year: "2015",
type: "Truck",
status: "new",
price: "$ 2000",
heart: "hearto",
selected: false
}
}
now in onPress do this
handleFavourite = (item) => {
const { id } = item;
this.setState({
localAdvertisement: this.state.localAdvertisement.map((item) => {
if(item.id === id){
return {
...item,
selected: !item.selected
}
}
return item
})
})
};
Now render like this
<TouchableOpacity onPress={() => this.handleFavourite(item)}>
<Icon
name={item.selected ? "heart" : 'hearto'}
type={"AntDesign"}
style={{ fontSize: 18 }}
/>
</TouchableOpacity>
Hope it will help you
Edit this function as follows:
handleFavourite = index => {
let updatedlocalAdversimentStates = this.state.localAdversiment;
updatedlocalAdversimentStates[index].heart = "heart";
this.setState(
{
localAdversiment: updatedlocalAdversimentStates
}
);
};

Categories