How to passe value from dropdown made by semantic ui in react - reactjs

I have problem with this select by semantic ui. I made object with values I mapping it, state is changing but value in Select is not updating - if I put props as default value, it is like hard coded, and not changing at all. So what i can do (e target value doesnt work) to pass the selected icon to change props state? Should i use hook?
import React from 'react';
import { Dropdown } from 'semantic-ui-react';
const Dropdown = () => {
let icons = [
{
"v1": "home",
"ico": "home"
},
{
"v1": "cart",
"ico": "cart"
},
{
"v1": "folder",
"ico": "folder"
},
{
"v1": "group",
"ico": "group"
},
{
"v1": "dollar",
"ico": "dollar"
},
{
"v1": "users",
"ico": "users"
},
{
"v1": "briefcase",
"ico": "briefcase"
},
{
"v1": "globe",
"ico": "globe"
},
{
"v1": "calendar",
"ico": "calendar"
},
{
"v1": "favorite",
"ico": "favorite"
},
];
const options = icons.map(({ v1, ico }) => ({ value: v1, icon: ico }))
return(
<div>
<Dropdown
text='Add icon'
icon='add circle'
floating
labeled
button
className='icon'
value={prop.icon}
options={options}
name='icon'
></Dropdown>
</div>
)
}

You can pass an onChange function to the component that receives two arguments: event and result. The result argument is an object that has a key value with the selected value of the dropdown. You then need to use the useState hook to save the selected value in the component state.
Hence, you could do something like this:
import {useState} from "react"
const [value, setValue] = useState("")
const handleChange = (e, result) => {
// result.value is the selected value from the Dropdown
setValue(result.value)
}
<Dropdown
onChange={handleChange}
/>

Related

How to dynamic render child Array component in react

I want to render dynamic component But I cannot able to render children component nextcomp[]. currently only first component Text rendering.
const item = [{
component: "text",
label: "Name",
Type: "text",
nextComp: [{
component: "checkbox",
label: "yes",
question: "Do you Play football",
type: "checkbox",
}, {
component: "text",
label: "Age",
Type: "text",
nextComp: [{
component: "checkbox",
label: "yes",
question: "Do you Play football",
type: "checkbox",
}, {
component: "text",
label: "Gender",
Type: "text",
}],
}],
}, ]
App.js I mapped like
{item.map(block => Components(block))}
I am rendering component like
const Components = {
Text: Text,
checkbox: Checkbox
};
export default block => {
if (typeof Components[block.component] !== "undefined") {
return React.createElement(Components[block.component], {
key: block,
block: block
});
}
return React.createElement(
() => <View>The component {block.component} has not been created yet.</View>,
{ key: block}
);
};
I think I sort of understand what you are going for here. I don't see where your recursive renderer function recurses on the block.nextComp array.
React.createElement
React.createElement(
type,
[props],
[...children]
)
Map the block.nextComp to this renderer and pass the result as the third argument.
const Components = {
Text: Text,
checkbox: Checkbox
};
const renderBlock = block => {
if (typeof Components[block.component] !== "undefined") {
return React.createElement(
Components[block.component],
{
key: block,
block: block
},
block.nextComp?.map(renderBlock) || null,
);
}
return React.createElement(
() => <View>The component {block.component} has not been created yet.</View>,
{ key: block}
);
};
export default renderBlock;
Update
I think you've a typo in your Components object, "Text" isn't a key referenced in your item array objects. Update the key to match usage.
const Components = {
text: Text,
checkbox: Checkbox
};
To make rendering the item array a little more clear, you might want to give the imported recursive renderer a more meaningful/clear name. Map the item array the same way the block.nextComp was mapped.
import renderBlock from '../path/to/renderBlock';
...
{item.map(renderBlock)}
See this running codesandbox demo:

Auto selected of value from options in react-select react

Problem Statement :
I am using react-select 2.4.1 for the Select dropdown.
I want to auto select the value from options array based on some condition, and that auto selected value should also get updated in the component state or vice versa.
How can I achieve that?
I have tried multiple ways, please help.
Thanks in advance.
Below is my code for the Select dropdown.
<Select
options={props.mercModeOptions}
onChange={(evt) => setSelectedMercMode(evt.value)}
selected={props.mercModeDefaultOpt}
/>
Below is the options array:
props.mercModeOptions = [
{
value: "first",
label: "first"
},
{
value: "second",
label: "second"
},
{
value: "third",
label: "third"
}
]
Value to be auto selected:
props.mercModeDefaultOpt = {
value: "third",
label: "third"
};
I have added sample codesandBox to achieve this.
We can store the default value in a variable using the useMemo hook and update the local state.
import Select from "react-select";
import { useEffect, useMemo, useState } from "react";
const dropDowonData = [
{ value: "first", label: "first" },
{ value: "second", label: "second" },
{ value: "third", label: "third" }
];
export default function App() {
const [selectedValue, setSelectedValue] = useState();
// This will run for only during the first render.
const defaultSelectedValue = useMemo(() => {
// to update the local state
setSelectedValue(dropDowonData[0]);
return dropDowonData[0];
}, []);
console.log(selectedValue);
return (
<div className="App">
<Select
defaultValue={defaultSelectedValue}
value={selectedValue}
onChange={(value) => setSelectedValue(value)}
name="Select"
options={dropDowonData}
/>
</div>
);
}

How can I add sub navigation to menu?

I have config file where I have configured the menuItems array as follows. Which is menu.json
{
"menuItems": [
{ "name": "Services", "link": "/services" },
{ "name": "References", "link": "/references" },
{ "name": "Careers", "link": "/careers" },
{ "name": "Our Story", "link": "/story" },
{ "name": "Contact Us", "link": "/contact" },
{ "name": "Guides", "link": "/guides"},
{ "name": "Blog", "link": "/blog" }
]
}
I have tried adding subMenuItems inside the menuItems array but so far it results in error in the query in the useMenu.js
{
"menuItems": [
{ "name": "Services", "link": "/services", "subMenuItems": [ {"name": "Page", "link": "/page"}] },
{ "name": "References", "link": "/references" },
{ "name": "Careers", "link": "/careers" },
{ "name": "Our Story", "link": "/story" },
{ "name": "Contact Us", "link": "/contact" },
{ "name": "Guides", "link": "/guides"},
{ "name": "Blog", "link": "/blog" }
]
}
Then in the querying the items inside the array here in the useMenu.js
import React from 'react'
import { useStaticQuery, graphql } from 'gatsby'
import { useLocale } from '../hooks/locale'
function useMenu() {
// Grab the locale (passed through context) from the Locale Provider
// through useLocale() hook
const { locale } = useLocale()
// Query the JSON files in <rootDir>/i18n/translations
const { rawData } = useStaticQuery(query)
// Simplify the response from GraphQL
const simplified = rawData.edges.map(item => {
return {
name: item.node.name,
menuItems: item.node.translations.menuItems,
}
})
// Only return menu for the current locale
const { menuItems } = simplified.filter(lang => lang.name === locale)[0]
return menuItems
}
export default useMenu
const query = graphql`
query useMenu {
rawData: allFile(filter: { sourceInstanceName: { eq: "menu" } }) {
edges {
node {
name
translations: childMenuJson {
menuItems {
link
name
subMenuItems {
link
name
}
}
}
}
}
}
}
`
And then adding the subMenuItems to the query. Is this wrong way to do it? How would I be able to add the sub menu there? The menu itself is set here in the navigation.js file and is following:
import React from 'react'
import useMenu from '../useMenu'
import * as S from './styled'
const Navigation = ({ isActive, handleToggleMenu }) => {
const [menuItems, subMenuItems] = useMenu()
return (
<>
<S.Navigation>
{menuItems.map((menu, index) => (
<S.NavigationLink
to={menu.link}
aria-label={menu.name}
activeClassName="active"
key={`${menu.link}${index}`}
>
{menu.name}
</S.NavigationLink>
))}
{subMenuItems.map((subMenu, index) => (
<S.NavigationLink
to={menu.link}
aria-label={subMenu.name}
activeClassName="active"
key={`${subMenu.link}${index}`}
>
{subMenu.name}
</S.NavigationLink>
))}
</S.Navigation>
</>
)
}
export default Navigation
The error I am getting is following: TypeError: Cannot read property '0' of undefined
const [menuItems, subMenuItems] = useMenu() here, you are importing your custom hook from ../useMenu. This hook, since it's a custom-coded one, only accepts the exported values from your useMenu.js file so, it doesn't allow that notation because you are only exporting menuItems:
function useMenu() {
// Grab the locale (passed through context) from the Locale Provider
// through useLocale() hook
const { locale } = useLocale()
// Query the JSON files in <rootDir>/i18n/translations
const { rawData } = useStaticQuery(query)
// Simplify the response from GraphQL
const simplified = rawData.edges.map(item => {
return {
name: item.node.name,
menuItems: item.node.translations.menuItems,
}
})
// Only return menu for the current locale
const { menuItems } = simplified.filter(lang => lang.name === locale)[0]
return menuItems // here, the only export
}
In addition, the way you use the state is not correct. When you set a state using useState hook, like:
const [value, setValue]= useState("hi");
Your state is held by value, so if you want to get the current state's value, you need to access to value, initially set to "hi". setValue is just a helper function that is used to set the new state, so if you want to set a new value, overriding "hi", you need to use the setter function setValue("new value").
Said that I can't know if your useMenu.js logic is correct, assuming that, I guess that you don't want two separate loops to get the subMenuItems data. You should do something like:
import * as S from './styled'
const Navigation = ({ isActive, handleToggleMenu }) => {
const menuItems = useMenu()
return (
<>
<S.Navigation>
{menuItems.map((menu, index) => {
if(menu.subMenuItems){
menu.subMenuItems.map(submenuItem=>{
return console.log(submenuItem);
})
}
return <S.NavigationLink
to={menu.link}
aria-label={menu.name}
activeClassName="active"
key={`${menu.link}${index}`}
>
{menu.name}
</S.NavigationLink>
})}
</S.Navigation>
</>
)
}
export default Navigation
Step by step, your state has changed to:
const menuItems = useMenu()
Since you are exporting menuItems, your data is perfectly valid there. You have your subMenuItems inside the menuItems.
In the same loop where you are iterating through menuItems, you have the nested property of subMenuItems so, if your menu (the iterable variable) has the subMenuItems property, you want to iterate again trough it to get them. In this case, I'm returning a console.log() but adapt it to your navigation menu:
if(menu.subMenuItems.length){
menu.subMenuItems.map(submenuItem=>{
return console.log(submenuItem);
})
}

How to display multiple selected values from a dropdown in React

I'm new to React and I wanted to create a dropdown which can select multiple values. For that I used the react-select plugin. In my React dev tool the selected values are getting stored but I'm not able to display all the selected values.
Any help is highly appreciated.
TIA
import React, { useState } from "react";
import Select from 'react-select'
const options = [
{ value: 'React', label: 'React' },
{ value: 'Vue', label: 'Vue' },
{ value: 'Angular', label: 'Angular' },
{ value: 'Java', label: 'Java' },
]
const [skills, setSkills] = useState([]);
const handleChange = (skill) => {
setSkills({skill})
console.log("skills", skill);
}
return (
<>
<h2>Please select all your skills</h2>
<form>
<Select
options={options}
onChange={handleChange}
isMulti={true}
value={value}
/>
<button>Next</button>
</form>
</>
)
}
export default UserSkills;
When I'm commenting isMulti prop, I'm getting that one selected value, but I'm not getting anything with isMulti prop.
You are controlling the Select component by giving it a value, and since you are not updating value in the handleChange function it will not be updated.
You could use the skills array as value instead and it will update as expected.
CodeSandbox
const options = [
{ value: "React", label: "React" },
{ value: "Vue", label: "Vue" },
{ value: "Angular", label: "Angular" },
{ value: "Java", label: "Java" }
];
function UserSkills() {
const [skills, setSkills] = useState([]);
const handleChange = (skills) => {
setSkills(skills || []);
};
return (
<>
<h2>Please select all your skills</h2>
<form>
<Select
options={options}
onChange={handleChange}
value={skills}
isMulti
/>
<button>Next</button>
</form>
</>
);
}
export default UserSkills;

React Native Props Not Saving into New Array

I am passing props to a nested component. The props are coming in correctly but I am unable to pass them to a new array like so:
import React, {useState, useEffect} from 'react';
import {StyleSheet, View} from 'react-native'
import MapView, {Marker} from 'react-native-maps';
const Map = ({navigation, locationsOne, locationsTwo, locationsThree}) => { //these are coming in correctly when I console.log ie: {"coords":{"accuracy":602,"altitude":0,"heading":0,"latitude":99.4210083,"longitude":-100.0839934,"speed":0},"mocked":false,"timestamp":1572363100628}
const [markers, setMarkers] = useState([
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
]);
return (
<MapView style={styles.map} initialRegion={currentLocation.coords}>
{markers.map((locationTEST) => (
console.log('location: ' + JSON.stringify(locationTEST)) //this returns nothing in the locations arrays ie: {"location":[],"title":"One"}
<MapView.Marker
title="This is a title"
description="This is a description"
coordinate={{
latitude: locationTEST.location.coords.latitude,
longitude: locationTEST.location.coords.longitude,
}}
/>
))}
</MapView>
);
the value of locationsOne looks like: {"coords":{"accuracy":602,"altitude":0,"heading":0,"latitude":99.4210083,"longitude":-100.0839934,"speed":0},"mocked":false,"timestamp":1572363100628}
How come I can't take the props and pass it into a new array (markers) array?
When <Map/> rendered at the first time, locationsOne still contain [].
When props (means locationsOne changed), state didn't changed.
So you should useEffect to update state when props changed.
const [markers, setMarkers] = useState ...
useEffect(() => {
const newMarkers = [
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
];
setMarkers(newMarkers);
}, [locationsOne, locationsTwo, locationsThree]);
Rather then setting the useEffect callback array [] (this was bogging down the system as this re-runs the locations every time they change which was causing the locations to be called 1400 times), I just needed to setMarkers() like so:
useEffect(() => {
const newMarkers = [
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
];
setMarkers(newMarkers);
}, []);

Resources