How to reset react-select value via state? - javascript

Feeding the react-select component the selected state to the value prop, makes it unable to select anything at all? I'm trying to feed the value-prop with the selected state so that i can reset react-select via setState. What am i doing wrong here?
Select Component with isMulti option:
import SelectForm from "react-select";
const Select = (props) => {
const options = props.options.map((option) => ({
value: option,
label: option.toLowerCase(),
}));
const costumStyles = {
container: (baseStyles) => ({ ...baseStyles, width: "100%" }),
control: (baseStyles) => ({
...baseStyles,
backgroundColor: "transparent",
borderStyle: "none",
borderRadius: "15px",
marginTop: "3px",
}),
singleValue: (baseStyles) => ({ ...baseStyles, color: "white" }),
};
const handleChange = (event) => {
props.onChangeOption(event);
};
return (
<div>
{props.isMulti ? (
<SelectForm
options={options}
onChange={handleChange}
styles={costumStyles}
placeholder={props.placeholder}
value={props.value}
isMulti
/>
) : (
<SelectForm
options={options}
onChange={handleChange}
styles={costumStyles}
placeholder={props.placeholder}
value={props.value}
/>
)}
</div>
);
};
export default Select;
The parent component which uses the Select component:
import React, { useState } from "react";
import Select from "../../input/Select";
const CreateJobPage3 = (props) => {
const [department, setDepartment] = useState();
const [subDepartment, setSubDepartment] = useState([]);
const departments = [jobDepartment1, jobDepartment2, jobDepartment3];
const subDepartments = [jobSubDepartment1, jobSubDepartment2, jobSubDepartment3];
const departmentHandler = (props) => {
setDepartment(props.value);
setSubDepartment([]);
};
const subDepartmentHandler = (props) => {
setSubDepartment(props.map((item) => item.value));
};
return (
<>
<Select
placeholder="Choose Department"
options={departments}
onChangeOption={departmentHandler}
value={department || ""}
/>
<Select
placeholder="Choose Sub-Departments"
options={subDepartments}
onChangeOption={subDepartmentHandler}
isMulti={true}
value={subDepartment || ""}
/>
</>
);
};
export default CreateJobPage3;

According to the docs of react-select they're expecting complete option to be passed in value array.
Say for example, we have options like
const options=[
{ value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true },
{ value: 'red', label: 'Red', color: '#0052CC', isDisabled: true }
];
then we have to pass value as,
value={[{ value: 'blue', label: 'Blue', color: '#0052CC', isDisabled: true }]}
Refer this example: https://codesandbox.io/s/17g0yy?module=/example.tsx
Try this,
const departmentHandler = (props) => {
setDepartment(props);
setSubDepartment([]);
};
const subDepartmentHandler = (props) => {
setSubDepartment(props);
};

Related

Adding handlers and state dynamically in React

I need to render plenty of inputs for every name of the array, but the problem is creating dynamically useState const and onChange handler for every rendered input.
I try to create handleChange key for every item in an array and pass it to input onChange but got the "String Instead Fuction" error. How to resolve the problem in another way and also avoid code duplication?
export const myArr = [
{ name: "Crist", data: "crist", color: "lightblue", handleChange: "cristHandleChange"},
{ name: "Ruby", data: "ruby", color: "lightpink", handleChange: "rubyHandleChange"},
{ name: "Diamond", data: "diamond", color: "white", handleChange: "diamondHandleChange"},
];
export const myComponent = () => {
const [cristQuantity, setCristQuantity] = useState(0);
const [rubyQuantity, setRubyQuantity] = useState(0);
const [diamondQuantity, setDiamondQuantity] = useState(0);
function cristHandleChange(event) {
setCristQuantity(event.target.value);
}
function rubyHandleChange(event) {
setRubyQuantity(event.target.value);
}
function diamondHandleChange(event) {
setDiamondQuantity(event.target.value);
}
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={item.handleChange} //???
/>
</div>
))
: null}
</>
);
};
You should create one handler for all inputs, and save values in a object with a key as item.data. Such way: {crist: 1, ruby: 3, diamond: 5}
export const myArr = [
{
name: "Crist",
data: "crist",
color: "lightblue"
},
{
name: "Ruby",
data: "ruby",
color: "lightpink"
},
{
name: "Diamond",
data: "diamond",
color: "white"
}
];
export function MyComponent() {
// Lazy initial state
// https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [quantities, setQuantities] = useState(() =>
myArr.reduce((initialQuantities, item) => {
initialQuantities[item.data] = 0;
return initialQuantities;
}, {})
);
// common handler for every onChange with computed property name
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names
const handleChange = (event) => {
setQuantities((prevQuantities) => ({
...prevQuantities,
[event.target.name]: event.target.value
}));
};
return (
<>
{Array.isArray(myArr)
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={handleChange}
value={quantities[item.data] || ""}
/>
</div>
))
: null}
</>
);
}
I haven't actually tested this but this is something I would do which will get you on the way.
export const myArr = [
{
name: `Crist`,
data: `crist`,
color: `lightblue`,
handleChange: `cristHandleChange`,
},
{
name: `Ruby`,
data: `ruby`,
color: `lightpink`,
handleChange: `rubyHandleChange`,
},
{
name: `Diamond`,
data: `diamond`,
color: `white`,
handleChange: `diamondHandleChange`,
},
]
export const myComponent = () => {
const [quantities, setQuantities] = useState({
crist: 0,
ruby: 0,
diamond: 0,
})
const onChangeHandler = ({ name, value }) => {
setQuantities((prevState) => ({ ...prevState, [name]: value }))
}
return (
<>
{myArr.length > 0
? myArr.map(({ data, name, color }, index) => {
// if you need to do an update to push more items to the object for any dynamic reason
if (!quantities.name)
setQuantities((prevState) => ({ ...prevState, [name]: 0 }))
return (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={data}>{name}</label>
<input
type="number"
name={name}
value={quantities.name}
style={{ background: color }}
onChange={(e) =>
onChangeHandler({ name, value: e.currentTarget.value })
}
/>
</div>
)
})
: null}
</>
)
}
You're passing a string (not a function) to onChange which is causing that problem.
To fix it, you can wrap all functions into another object
const onChangeFunctions = {
cristHandleChange: (event) => {
setCristQuantity(event.target.value);
},
rubyHandleChange: (event) => {
setRubyQuantity(event.target.value);
},
diamondHandleChange: (event) => {
setDiamondQuantity(event.target.value);
},
};
and call onChangeFunctions[item.handleChange] like below
export const myArr = [
{
name: "Crist",
data: "crist",
color: "lightblue",
handleChange: "cristHandleChange",
},
{
name: "Ruby",
data: "ruby",
color: "lightpink",
handleChange: "rubyHandleChange",
},
{
name: "Diamond",
data: "diamond",
color: "white",
handleChange: "diamondHandleChange",
},
];
export const myComponent = () => {
const [cristQuantity, setCristQuantity] = useState(0);
const [rubyQuantity, setRubyQuantity] = useState(0);
const [diamondQuantity, setDiamondQuantity] = useState(0);
const onChangeFunctions = {
cristHandleChange: (event) => {
setCristQuantity(event.target.value);
},
rubyHandleChange: (event) => {
setRubyQuantity(event.target.value);
},
diamondHandleChange: (event) => {
setDiamondQuantity(event.target.value);
},
};
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={onChangeFunctions[item.handleChange]}
/>
</div>
))
: null}
</>
);
};
Let me start by saying that you might want to use a library like React Hook Form for this, although, if this is the only form and you don't need all the fancy features (or additional bundle size), you can do it like this as well.
The first step is to store your form data in an Object. After this change, you can use a single useState({}) to store and read your form data and drastically simplifies your handlers.
For example:
export const myArr = [
{ name: "Crist", data: "crist", color: "lightblue"},
{ name: "Ruby", data: "ruby", color: "lightpink"},
{ name: "Diamond", data: "diamond", color: "white"},
];
// generate Object with data and initialValue or empty string
// e.g. `{ 'crist': '', 'ruby': '', 'diamond': '' }`
const getInitialFormValues = (arr) => Object.fromEntries(
arr.map(({ data, initialValue }) => [data, initialValue || ''])
);
export const MyComponent = () => {
const [formValues, setFormValues] = useState(getInitialFormValues(myArr));
function handleChange(event) {
// update the changed form value
setFormValues(current => ({
...current, // other form values
[event.target.name]: event.target.value // updated value
}));
}
return (
<>
{myArr
? myArr.map((item, index) => (
<div className="main-inputs__wrapper" key={`item${index}`}>
<label htmlFor={item.data}>{item.name}</label>
<input
type="number"
name={item.data}
style={{ background: item.color }}
onChange={handleChange}
value={formValues[item.data]}
/>
</div>
))
: null}
</>
);
};

React: Entering boolean 'true' as prop end up as 'false' in the component

I am utterly confused by this. I have a select box component where I have a selected prop. when true I show a checkmark in the box, if false, not. Now the issue that I have is that after three times clicking it doesn't toggle anymore.
The strangest thing is that I do pass a true boolean to the component's 'selected' prop (see logs), but when I make a log of the 'selected' prop in that child component, it says it is false.
Anyone has a clue why this could be different?
Result of the logs seen below
Parent component: Services.tsx
import React, { useReducer } from "react";
import { makeStyles } from "#material-ui/core";
import { ToggleBox } from "components/ToggleBox";
const useStyles = makeStyles((theme) => ({
container: {
display: "flex",
},
}));
const servicesReducer = (state, action) => {
switch (action.type) {
case "toggle option":
const isCurrentlySelected = state.selectedOptions.includes(
action.payload.name
);
let newSelectedOptions = state.selectedOptions;
if (isCurrentlySelected) {
newSelectedOptions = newSelectedOptions.filter(
(item) => item !== action.payload.name
);
} else {
newSelectedOptions.push(action.payload.name);
}
return {
...state,
selectedOptions: newSelectedOptions,
};
case "add options":
return {
...state,
};
}
};
export const Services = () => {
const classes = useStyles();
const [state, dispatch] = useReducer(servicesReducer, {
financialPlanning: {
description: "",
minHours: null,
maxHours: null,
minPrice: null,
maxPrice: null,
},
selectedOptions: [],
});
const check = state.selectedOptions.includes("financialPlanning");
console.log("check", check);
console.log("check2", state);
return (
<div className={classes.container}>
<ToggleBox
selected={check}
onClick={() => {
console.log("click");
dispatch({
type: "toggle option",
payload: { name: 'financialPlanning' },
});
}}
title="Financiƫle planning"
>
Hey
</ToggleBox>
</div>
);
};
child component: ToggleBox.tsx
import React from 'react';
import { Box, Card, CardContent, Typography } from '#material-ui/core';
import { makeStyles } from '#material-ui/core/styles';
import RadioButtonUncheckedIcon from '#material-ui/icons/RadioButtonUnchecked';
import CheckCircleOutlineIcon from '#material-ui/icons/CheckCircleOutline';
import { responsivePadding } from 'helpers';
export interface ToggleBoxProps {
title: string;
description?: string;
rightIcon?: React.ReactElement;
selected: boolean;
focused?: boolean;
children?: React.ReactNode;
onClick?: () => void;
}
const useStyles = makeStyles(theme => ({
root: ({ selected, focused }: ToggleBoxProps) => {
let borderColor = theme.palette.grey[300];
if (focused) {
borderColor = theme.palette.primary.main;
} else if (selected) {
// eslint-disable-next-line prefer-destructuring
borderColor = theme.palette.grey[500];
}
return {
border: `1px solid ${borderColor}`,
height: '100%',
};
},
content: {
height: '90%',
display: 'flex',
flexDirection: 'column',
},
header: {
display: 'flex',
cursor: 'pointer',
flexDirection: 'row',
justifyContent: 'space-between',
paddingBottom: theme.spacing(2),
marginBottom: theme.spacing(2),
borderBottom: `1px solid ${theme.palette.divider}`,
color: theme.palette.text.secondary,
},
title: {
flex: 1,
marginLeft: theme.spacing(2),
},
}));
export const ToggleBox: React.FC<ToggleBoxProps> = (
props: ToggleBoxProps,
) => {
console.log('props toggleBox', props);
const { title, description, rightIcon, selected, children, onClick } = props;
console.log('selected check prop Togglebox', selected);
const classes = useStyles(props);
return (
<Card className={classes.root}>
<CardContent className={classes.content}>
<Box className={classes.header} onClick={onClick}>
{selected ? <CheckCircleOutlineIcon /> : <RadioButtonUncheckedIcon />}
<Typography className={classes.title} color='textSecondary'>
{title}
</Typography>
{rightIcon}
</Box>
<Typography variant='body2' color='textSecondary'>
{description}
</Typography>
{selected && children}
</CardContent>
</Card>
);
};
You seem to be mutating your state when adding a value to the selectedOptions array. .push mutates an existing array in-place.
case "toggle option":
const isCurrentlySelected = state.selectedOptions.includes(
action.payload.name
);
let newSelectedOptions = state.selectedOptions; // <-- saved reference to state
if (isCurrentlySelected) {
newSelectedOptions = newSelectedOptions.filter(
(item) => item !== action.payload.name
);
} else {
newSelectedOptions.push(action.payload.name); // <-- mutation!
}
return {
...state,
selectedOptions: newSelectedOptions,
};
In either case of adding or removing you necessarily need to return a new array reference. You can use Array.prototype.concat to add a value to an array and return a new array reference.
case "toggle option":
const isCurrentlySelected = state.selectedOptions.includes(
action.payload.name
);
let newSelectedOptions = state.selectedOptions;
if (isCurrentlySelected) {
newSelectedOptions = newSelectedOptions.filter(
(item) => item !== action.payload.name
);
} else {
newSelectedOptions.concat(action.payload.name); // <-- add to and return new array
}
return {
...state,
selectedOptions: newSelectedOptions,
};

I want to clear selected data in onClick react-select

I am using the react-select dropdown what my task is I need to clear the selected field in onClick of reset button mean like if I select on the name in the drop-down it will visible in what I selected so I need to clear the selected field or after clear placeholder filed will visible then again am I am able to select field
const [data, setData] = React.useState([]);
const [value, setValue]= React.useState('')
const handleSelectChange = (object, action) => {
let name = action.name;
let value = object;
setFormData((prevFormData) => ({
...prevFormData,
[name]: object,
}));
};
const handleSelectChangeL = (object, action) => {
setIndex(data[object.id]);
setUserlevel(null);
let name = action.name;
let value = object.value;
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
const reset = () => {
setValue('')
};
<Select
className="drop-down"
options={screenType}
name="screen"
value={value}
onChange={handleSelectChange}
placeholder="Screen Type"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7",
},
})}
></Select>
<Select
className="drop-down"
options={data?.map((data, index) => ({
value: data.username,
label: data.username,
id: index,
}))}
name="user"
value={data.username}
onChange={handleSelectChangeL}
placeholder="User Name"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7",
},
})}
></Select>
<button
className="dash-button-1"
type="submit"
variant="contained"
onClick={reset}
>
Reset
</button>
You will have to toggle the state of value prop in the <Select>tag. You may define a state like const [value, setValue]= useState('') and change its value based on the onChange function.
Your reset function could be like this:
const reset = () => {
setValue('')
};
This will again reset the value of the Select Tag.
Update your Select value field with the state value like below,
import { useEffect, useState } from "react";
import "./styles.css";
import Select from "react-select";
const data = [
{
username: "jerry"
},
{
username: "Tim"
},
{
username: "Ravi"
}
];
export default function App() {
const [value, setValue] = useState("");
const reset = () => {
setValue("");
};
const handleSelectChange = (selected) => {
setValue(selected);
};
return (
<div>
<Select
className="drop-down"
options={data?.map((data, index) => ({
value: data.username,
label: data.username,
id: index
}))}
name="user"
value={value} // <---- CHANGE HERE
onChange={handleSelectChange}
placeholder="User Name"
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
text: "black",
primary25: "#d6fdf7",
primary: "#0bb7a7",
primary50: "#d6fdf7"
}
})}
></Select>
<button
className="dash-button-1"
type="submit"
variant="contained"
onClick={reset}
>
Reset
</button>
</div>
);
}
codesandbox - https://codesandbox.io/s/nervous-chaplygin-y5lqx?file=/src/App.js:0-1181
If you will use useEffect then i think your issue will be resolved.
useEffect(()=>{
},[value])
//i will suggest to store the name in value and then it will work (setValue(data.username))

react-select: (multiselect) How to pass both event object & selectedOptions to event handler?

I have multiple Select fields in my App component. Since it throws an error if I pass the event object(to access 'id' of each component) as a second parameter to the event handler(along with selectedOptions), I cannot have a single event handler for all the Select components. Instead, I currently need a separate event handler for each component, so that I can store the selected options of each component in different arrays in component state. If I could use event.target.id, I could do the same job with just one function.
codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js
import React from 'react'
import Select from 'react-select';
const options = [
{ value: 'red', label: 'red' },
{ value: 'blue', label: 'blue' },
{ value: 'green', label: 'green' }
];
class App extends React.Component {
state = {
selectedOptionsFIRST: [],
selectedOptionsSECOND: [],
}
handleChangeFIRST = (selectedOptions) => {
this.setState({ selectedOptionsFIRST: selectedOptions });
}
handleChangeSECOND = (selectedOptions) => {
this.setState({ selectedOptionsSECOND: selectedOptions });
}
render() {
return (
<React.Fragment>
<Select
id={0}
isMulti
value={this.state.selectedOptionsFIRST}
onChange={this.handleChangeFIRST}
options={options}
/>
{this.state.selectedOptionsFIRST.map(o => <p>{o.value}</p>)}
<Select
id={1}
isMulti
value={this.state.selectedOptionsSECOND}
onChange={this.handleChangeSECOND}
options={options}
/>
{this.state.selectedOptionsSECOND.map(o => <p>{o.value}</p>)}
</React.Fragment>
);
}
}
What about passing the state field in the handler?
import React from "react";
import Select from "react-select";
const options = [
{ value: "red", label: "red" },
{ value: "blue", label: "blue" },
{ value: "green", label: "green" }
];
class App extends React.Component {
state = {
selectedOptionsFIRST: [],
selectedOptionsSECOND: []
};
handleChange = (id, selectedOptions) => {
this.setState({ [id]: selectedOptions });
};
render() {
return (
<React.Fragment>
<Select
isMulti
value={this.state.selectedOptionsFIRST}
onChange={(e) => {this.handleChange('selectedOptionsFIRST',e);}}
options={options}
/>
{this.state.selectedOptionsFIRST.map((o) => (
<p>{o.value}</p>
))}
<Select
isMulti
value={this.state.selectedOptionsSECOND}
onChange={(e) => {this.handleChange('selectedOptionsSECOND',e);}}
options={options}
/>
{this.state.selectedOptionsSECOND.map((o) => (
<p>{o.value}</p>
))}
</React.Fragment>
);
}
}
export default App;

The data sent from action is not received by reducer

I am using redux with my react application. I am trying to get the data from my reducer but when I am trying to do this. I am getting some error.
Uncaught Error: Given action "RECEIVE_CATEGORY_NAME", reducer
"categoriesReducer" returned undefined. To ignore an action, you must
explicitly return the previous state. If you want this reducer to hold
no value, you can return null instead of undefined.
the logic written is working fine in case of influencersNameReducer but is showing an error for categoriesReducer
home_reducer.js
import { RECEIVE_INFLUENCERS_NAME, RECEIVE_CATEGORY_NAME } from './home_actions';
export const influencersNameReducer = (state = [], { type, influencers }) => {
console.log(influencers)
return type === RECEIVE_INFLUENCERS_NAME ? influencers : state
}
export const categoriesReducer = (state = [], { type, category }) => {
console.log(type, category)
return type === RECEIVE_CATEGORY_NAME ? category : state
}
home_actions.js
export const RECEIVE_INFLUENCERS_NAME = 'RECEIVE_INFLUENCERS_NAME'
export const RECEIVE_CATEGORY_NAME = 'RECEIVE_CATEGORY_NAME';
const receiveInfluencersName = influencers => ({ type: RECEIVE_INFLUENCERS_NAME, influencers })
const receiveCategoryName = categories => ({ type: RECEIVE_CATEGORY_NAME, categories })
export const fetchInfluencers = _ => dispatch => {
$.ajax({
method: 'get',
url: 'vip_api/influencers',
data: { name: _ },
success(influencers) {
dispatch(receiveInfluencersName(influencers))
},
error({ responseJSON, statusText }) {
dispatch(receiveServerErrors(responseJSON || [statusText]))
}
})
}
export const fetchCategories = _ => dispatch => {
$.ajax({
method: 'get',
url: 'vip_api/categories',
data: { name: _ },
success(categories) {
dispatch(receiveCategoryName(categories))
},
error({ responseJSON, statusText }) {
dispatch(receiveServerErrors(responseJSON || [statusText]))
}
})
}
store.js
import {influencersNameReducer, categoriesReducer} from './Vvip/Home/home_reducer';
import { composeWithDevTools } from 'redux-devtools-extension';
const reducer = combineReducers({
categoriesReducer,
influencersNameReducer,
})
const composeEnhancers = composeWithDevTools({
// Specify name here, actionsBlacklist, actionsCreators and other options if needed
});
export default (state = {}) => (
createStore(reducer, state, composeEnhancers(applyMiddleware(errorMiddleware, timeoutMiddleware, thunk)))
)
index.js
import React, { Component } from 'react'
import Select, { components } from 'react-select'
import DateRange from '../../shared/_date_range';
import moment from 'moment';
import {ethnicities, ageRanges, isoCountries} from '../../constants';
import { connect } from 'react-redux';
import {fetchInfluencers, fetchCategories} from './home_actions';
class InfluencersForm extends Component {
constructor() {
super();
this.state = {
demography: null,
dates : {
startDate: moment(),
endDate: moment()
},
influencersName: [],
}
}
handleInfluencerName = event => {
this.props.dispatch(fetchInfluencers(event))
}
handleSelectedInfluencer = event => {
console.log(event)
this.setState({
isMenuOpenInfluencer : false
})
}
componentWillReceiveProps(newProps) {
console.log(newProps);
if (newProps.influencersNameReducer && newProps.influencersNameReducer.length) {
this.setState({
influencersName: newProps.influencersNameReducer.map((influencer, index) => {
return ({ value: influencer, label: influencer })
}),
})
}
}
handleInfluencerType = event => {
console.log(event)
}
handleInfluencerCountry = event => {
console.log(event)
}
handleInfluencerSubscribers = event => {
console.log(event)
}
handleInfluencerVideosCreated = event => {
console.log(event)
}
handleInfluencerCategory = event => {
console.log(event)
this.props.dispatch(fetchCategories(event))
}
onDemographyChange = event => {
console.log(event.currentTarget.value)
this.setState({
demography: event.currentTarget.value
})
}
handleInfluencerAge = event => {
console.log(event)
}
handleInfluencerGender = event => {
console.log(event)
}
handleInfluencerEthnicity = event => {
console.log(event)
}
updateDates = event => {
console.log(event)
this.setState({
dates: event
})
}
render() {
const influencersType = [
{ value: 'a', label: 'Type A' },
{ value: 'b', label: 'Type B' },
{ value: 'c', label: 'Type C' }
]
const influencersCategory = [
{ value: 'a', label: 'Type A' },
{ value: 'b', label: 'Type B' },
{ value: 'c', label: 'Type C' }
]
const influencersAge = ageRanges.map(age => ({ value: age, label: age }))
const influencersGender = [
{ value: 'male', label: 'Male' },
{ value: 'female', label: 'Female' }
]
const influencersKeywords = [
{ value: 'youtuber', label: 'Youtuber' },
{ value: 'vlogger', label: 'Vlogger' }
]
const influencersCountry = Object.keys(isoCountries).map(code => ({ value: code, label: isoCountries[code] }))
const DropdownIndicator = (props) => {
return components.DropdownIndicator && (
<components.DropdownIndicator {...props}>
<i className="fa fa-search" aria-hidden="true" style={{ position: 'initial', color: 'black' }}></i>
</components.DropdownIndicator>
);
};
return (
<div className='home-forms influencer-form'>
<div className='display-flex'>
<Select
options={this.state.influencersName}
onChange={this.handleSelectedInfluencer}
closeMenuOnSelect = {true}
isSearchable={true}
components={{ DropdownIndicator }}
onInputChange = {this.handleInfluencerName}
placeholder={'Start Typing Influencers Name'}
classNamePrefix="vyrill"
className="influencers influencers-icon-name" />
<Select
options={influencersType}
onChange={this.handleInfluencerType}
placeholder='Type of Influencers'
classNamePrefix="vyrill"
className="influencers influencers-icon-type" />
<Select
options={influencersCountry}
onChange={this.handleInfluencerCountry}
isSearchable={true}
components={{ DropdownIndicator }}
placeholder='Start Typing Country'
classNamePrefix="vyrill"
className="influencers influencers-icon-country" />
</div>
<div className='display-flex' style={{ marginTop: 32 }}>
<Select
options={influencersType}
onChange={this.handleInfluencerSubscribers}
placeholder='Number of Subscribers'
classNamePrefix="vyrill"
className="influencers influencers-icon-type" />
<Select
options={influencersType}
onChange={this.handleInfluencerVideosCreated}
placeholder='Number of Videos Created'
classNamePrefix="vyrill"
className="influencers influencers-icon-videos-created" />
<Select
options={influencersCategory}
onChange={this.handleInfluencerCategory}
onInputChange = {this.handleInfluencerCategory}
isSearchable={true}
components={{ DropdownIndicator }}
placeholder='Start Typing Category'
classNamePrefix="vyrill"
className="influencers influencers-icon-country influencers-icon-category" /> {/* remove influencers-icon-country later */}
</div>
<div style={{ marginTop: 50 }}>
<div className="display-flex">
<div className="icon-subscribers" style={{ marginTop: 4 }}></div>
<div style={{ fontWeight: 700, marginTop: 4 }}>Demographics</div>
<div className="radio-container">
<label>
<div style={{ fontSize: 14, marginTop: 4 }}>By influencers</div>
<input
type="radio"
name="demographics"
value="influencers"
checked={this.state.demography === 'influencers'}
onChange={this.onDemographyChange} />
<span className="custom-radio">
</span>
</label>
</div>
<div className="radio-container">
<label>
<div style={{ fontSize: 14, marginTop: 4 }}>By people in videos</div>
<input
type="radio"
name="demographics"
value="people in videos"
checked={this.state.demography === 'people in videos'}
onChange={this.onDemographyChange} />
<span className="custom-radio"></span>
</label>
</div>
</div>
</div>
<div className="display-flex" style={{ marginTop: 40 }}>
<Select
options={influencersAge}
onChange={this.handleInfluencerAge}
placeholder='Age'
classNamePrefix="vyrill"
className="influencers" />
<Select
options={influencersGender}
onChange={this.handleInfluencerGender}
placeholder='Gender'
classNamePrefix="vyrill"
className="influencers" />
<Select
options={ethnicities}
onChange={this.handleInfluencerEthnicity}
placeholder='Ethnicity'
classNamePrefix="vyrill"
className="influencers" />
</div>
<div style={{marginTop: 50}}>
<div style={{display: 'inline'}}>Contains keywords (in transcript):</div>
<span className="icon-info"></span>
<Select
options={influencersKeywords}
onChange={this.handleInfluencerName}
isSearchable={true}
classNamePrefix="vyrill"
placeholder= {" "}
className="influencers influencers-keywords"
styles = {{marginTop: 10}}/>
</div>
<div style={{marginTop: 50}} className="date-picker">
<div>Posted content time range</div>
<DateRange dates={ this.state.dates } updateDates={ this.updateDates }/>
<div className="icon-arrow-right"></div>
</div>
</div>
)
}
}
const mapStateToProps = ({ influencersNameReducer, categoriesReducer }) => ({
influencersNameReducer,
categoriesReducer
})
export default connect(mapStateToProps)(InfluencersForm)
You need to modify your reducer as:
export const influencersNameReducer = (state = [], { type, influencers }) => {
switch(type) {
case RECEIVE_INFLUENCERS_NAME:
return influencers;
default:
return state;
}
}
export const categoriesReducer = (state = [], { type, category }) => {
switch(type) {
case RECEIVE_CATEGORY_NAME:
return category;
default:
return state;
}
}
On every action the dispatcher goes to every reducer. Since in your code the influencersNameReducer reducer was not doing anything for type RECEIVE_CATEGORY_NAME thus returning undefined. So you were getting the error. Using switch case is the way to do this.

Categories