Controlled dropdown selection with React, Redux, and Semantic-UI-React

Will Ley
4 min readMay 4, 2019

--

Welcome back for the long delayed part 2 of using Semantic UI Multi-select drop down with user added input with Redux!

I’m assuming a few things here. The first is that you’re familiar with Redux and have decent sense of some of the moving parts like Map State to Props and Dispatch Actions. If not, feel free to read on, but understand I didn’t focus too much on the structure of these topics. That said, I do have some conventions in my programing with Redux.

The first is I use a type.js file which exports constants for error handling. I’m not the best speller and it helps so that I don’t have to keep typing strings. Here’s an example:

export const SET_DROPDOWN_VALUES = "SET_DROPDOWN_VALUES"

So you’ll see this in both my actions file and my reducer file as:

import {
SET_DROPDOWN_VALUES,
ADD_DROPDOWN_VALUE
} from './actions/types'

The second is that I use an index.js file in my actions folder. This lets me import all actions to components for dispatching. The sequence looks something akin to:

//redux/actions/dropDownActions.js
export const setCurrentSelectedValues = (e, data) =>{
return{ type: SET_DROPDOWN_VALUES, payload: data.value}
}
//redux/actions/index.js
export * from './dropDownActions'
//containers/MultiSelectDropdown.js
import * as actions from '../redux/actions'
export default connect(mapSTP, actions)(MultiSearchDropdown)

Awesome! Now that we know each other a bit, let us start the walk through.

Semantic UI React Component:

There are a few quirky things with using Semantic UI React components. The biggest and most applicable for this example is that there are two separate events that get passed to the call back. The first is Reacts ‘normal’ synthetic event. The second is Semantic’s own event. It looks something link this:

onAddItem={(e, data)=>{console.log(e, data)}}

I’ve found that data.value is usually the info you’re looking for. The entire component will look like this:

import React from 'react'
import { Dropdown } from 'semantic-ui-react'
import {connect} from 'react-redux'
import * as actions from '../redux/actions'
const MultiSearchDropdown = (props) => (
<Dropdown
placeholder='Some placeholder text'
fluid
multiple
search
selection

options={props.options} // <--- this is the connected options
// ARRAY. This needs the structure of:
// [
// {key: 1,
// text: "this is what's displayed",
// value: "this is the Semantic UI Event value"}
// ]
value={props.selectedValues}//<-this an array of the values
// from the option object
allowAdditions // <- this allows user to add items and triggers
// the onAddItem function on click of 'enter'


onAddItem={(e, data)=>{props.addUserDropdownOption(e, data)}}
// ^-- you want to use this to create
// a new option object and add it
// to the options array
// `e` here is React's synthetic event
// `data` is the event created by the Semantic UI component
// The data.value will be the text a user inputs
onChange={(e, data) =>{props.setCurrentSelectedValues(e, data)}} // ^-- for mulit-Select this returns an array of
// the values currently in the selection bar
/>
)
const mapSTP = (state)=>{
return{
options: state.options,
selectedValues: state.selectedValues
}
}
export default connect(mapSTP, actions)(MultiSearchDropdown)

If it’s a bit easier to look at in a code editor or in a repo look for it here.

The options prop is an array of option objects. Each of the objects in the array follows the pattern of:

{

key: someKey,

text: "This is displayed",

value: "this is used to select which items are displayed"

}

The way you control this component is by passing an array to the value prop. Each element in the array is the ‘value’ from the object in the options array. It will then automatically display the text from each of those objects and hold them as selected.

The second aspect of the controlled menu is manipulating the onChange callback prop.

onChange={(e, data) =>{props.setCurrentSelectedValues(e, data)}}

The data.value here is an array with all of the selected values including that of the most recent SELECTED item. If a user adds an item, this will include the string the user has typed even if all the other values are of a different type.

To have a controlled version that takes in user input, two things must happen.

First:

The onAddItem call back must create an option object with a value of what the user typed in. This must then be added to the options array.

//redux/actions/dropDownActions.jsexport const addUserDropdownOption = (e, data)=>{    const userAddedItem = {
key: data.value,
text: data.value,
value: data.value
}
return {type: ADD_DROPDOWN_VALUE, payload: userAddedItem}}--------------------------------------------------------------------
//redux/reducers.js
//manages the options array
const optionsReducer = (state= options, action)=>{
switch(action.type){
case ADD_DROPDOWN_VALUE:
return [...state, action.payload]
default:
return state
}
}

Second:

The onChange callback must update the array that is given to the value prop to include the string the user has typed in.

//redux/actions/dropDownActions.js// this action sets the current selects valuesexport const setCurrentSelectedValues = (e, data) =>{
//notice here that we're using the semantic-ui data-event not
//the react synthetic event.
return{ type: SET_DROPDOWN_VALUES, payload: data.value}
}
-------------------------------------------------------------------
//redux/reducers.js
//manages the selected values array
const selectedValuesReducer = (state=[], action)=>{
switch(action.type){
case SET_DROPDOWN_VALUES:
return action.payload
default:
return state
}
}

With these to additions you can control user input as well as existing dropdown options.

I hope this helps as this can be a frustrating component to manage the first time. Thanks for reading and if you have any comments or suggestions, please leave them below. Happy coding!

--

--