Im developing a products table with checkboxes on the side, the check box job is to send the Id of the choosen product once its clicked to it's grandfather so i can build an array of the choosen ones and send them via api.
Its built like this:
grandfather - Table page component.
father - The table itself.
child - The checkbox component.
basically I'm having trouble how to pass the information, i know i should use context api but the syntax is confusing me, here's the code:
Grandfather:
interface Istate {
Select: boolean;
SelectT: boolean;
SelectI: boolean;
Loader: boolean;
numOfProds: number;
listing: any;
checkBoxId: any;
prodName: string;
quantity: number;
price: number;
TempProdName: string;
TempQuantity: number;
TempPrice: number;
}
interface Iprops {
id: string;
name: string;
}
class Products extends Component<Iprops, Istate> {
state = {
Select: false,
SelectT: false,
SelectI: false,
Loader: false,
numOfProds: 0,
listing: Array,
checkBoxId: '',
prodName: '',
quantity: 0,
price: 0,
TempProdName: '',
TempQuantity: 0,
TempPrice: 0,
};
async componentDidMount() {
this.showLoader();
const listing = await AllProductsService.AllProducts();
this.setState({ listing });
console.log(listing);
this.setState({ numOfProds: listing.length });
this.hideLoader();
}
toggleSelect = () => {
const { Select } = this.state;
this.setState({ Select: !Select });
};
toggleSelect2 = () => {
const { SelectT } = this.state;
this.setState({ SelectT: !SelectT });
};
toggleSelect3 = () => {
const { SelectI } = this.state;
this.setState({ SelectI: !SelectI });
};
showLoader = () => {
this.setState({ Loader: true });
};
hideLoader = () => {
this.setState({ Loader: false });
};
CancelValue = () => {
const { prodName, quantity, price, TempPrice, TempProdName, TempQuantity } = this.state;
this.setState({ TempProdName: prodName });
this.setState({ TempQuantity: quantity });
this.setState({ TempPrice: price });
};
changeValue = (checkBoxId: any, value: any) => {
this.setState({
[checkBoxId]: value,
} as any);
};
render() {
const {
Select,
SelectT,
SelectI,
listing,
numOfProds,
Loader,
checkBoxId,
prodName,
quantity,
price,
TempProdName,
TempQuantity,
TempPrice,
} = this.state;
const { name, id } = this.props;
return (
<ProductTableProvider
value={{
prodName,
quantity,
price,
checkBoxId,
changeValue: this.changeValue,
}}
>
<Breadcrumb path1="/overview" one="Dashboard" path2="/dashboard/products" two="All Products" />
<InsideWrapper>
<Platform>
<h2>Products</h2>
<br />
<p>Manage your products</p>
<CardStat header="Total" numOf={numOfProds} page="Products" />
<CardStat header="Ebay" numOf={numOfProds} page="Products" />
<div className="col-sm text-center new w-100">
<div className="text-right mb-4">
<GreenButton onClick={this.toggleSelect3}>Export to Ebay</GreenButton>
<SimpleModal isOpen={SelectI} close={this.toggleSelect3} whatToDo={`Export ${name} to Ebay?`}>
<YesNoButton name={name} id={id} />
</SimpleModal>
<RegularButton onClick={this.toggleSelect}>Save</RegularButton>
<SimpleModal isOpen={Select} close={this.toggleSelect} whatToDo="Are you sure you want to save?">
<YesNoButton name={name} id={id} />
</SimpleModal>
<OrangeButton onClick={this.CancelValue}>Cancel</OrangeButton>
<DeleteButton onClick={this.toggleSelect2}>Delete</DeleteButton>
<SimpleModal isOpen={SelectT} close={this.toggleSelect2} whatToDo="Are you sure you want to delete?">
<YesNoButton name={name} id={id} />
</SimpleModal>
</div>
<Card>{Loader ? <Loading /> : <DatatablePage listing={listing} />}</Card>
</div>
</Platform>
</InsideWrapper>
</ProductTableProvider>
);
}
}
export default Products;
Father:
const DatatablePage = (props: any) => {
const { listing } = props;
const rows = Array.isArray(listing)
? listing.map((val: any) => {
return {
select: <CheckBoxComp value={false} id={val._id} />,
name: <TableText value={val.name} id={val._id} />,
barcode: val._id,
category: val.category,
image: <ImageSec src={ImageProd} />,
unitsInStock: <TableText value={val.unitsInStock} id={val._id} />,
price: <TableText value={val.price} id={val._id} />,
more: <ButtonsPopUp name={val.name} id={val._id} />,
};
})
: [];
const data = {
columns: [
{
label: '',
field: '',
sort: 'disabled',
width: 20,
},
{
label: 'Name',
field: 'name',
sort: 'asc',
width: 100,
},
{
label: 'Barcode',
field: 'barcode',
sort: 'asc',
width: 100,
},
{
label: 'Category',
field: 'category',
sort: 'asc',
width: 100,
},
{
label: 'Images',
field: 'images',
sort: 'asc',
width: 100,
},
{
label: 'Quantity',
field: 'unitsInStock',
sort: 'asc',
width: 150,
},
{
label: 'Price',
field: 'price',
sort: 'asc',
width: 150,
},
{
label: '...',
field: 'more',
sort: 'disabled',
width: 100,
},
],
rows,
};
return (
<Rules>
<MDBDataTable
entriesLabel="Show Products"
infoLabel={['Showing', 'to', 'of', 'Products']}
fixed
responsive
btn
sortable
hover
data={data}
theadColor="white"
/>
</Rules>
);
};
export default DatatablePage;
Child:
interface Istate {
checked: boolean;
products?: any[];
}
interface Iprops {
id: any;
value: any;
changeValue?: (checkBoxId: string, value: any) => void;
}
class CheckBoxComp extends Component<Iprops, Istate> {
state = {
checked: true,
products: [] as any,
};
addOne = (id: any, checked: any) => {
let { products } = this.state;
const newObj = { id, checked };
products = products.concat(newObj);
this.setState({ products }, () => {
console.log(products);
});
};
isChecked = (id: any) => {
const { checked, products } = this.state;
const { changeValue } = this.props;
console.log(id);
this.setState({
checked: !checked,
});
if (changeValue) {
changeValue(id, checked);
}
this.addOne(id, checked);
};
render() {
const { id, value } = this.props;
const { checked } = this.state;
return (
<Fragment>
<Checkbox>
<span />{' '}
<label className="checkbox-wrapper">
<span className="display" />
<Inputt type="checkbox" value={checked} onChange={this.isChecked.bind(this, id)} />
<span className="checkmark" />
</label>
</Checkbox>
</Fragment>
);
}
}
export default CheckBoxComp;
any help wrapping the code correctly using context api?
Related
I define a const varible that contains table columns, which was needed to invoke the function in react component. This is my code snippet looks like:
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id'
},
{
title: 'edit',
key: 'action',
render: (text, record) => (
<span>
<Button type='link'>detail</Button>
<Divider type='vertical' />
<Button onClick={this.editApp} type='link'>edit</Button>
</span>
)
}
]
class App extends Component {
state = {
loading: false,
pageNum: 1,
pageSize: 10,
isAddModalVisible: false,
isEditModalVisible: true
}
enterLoading = () => {
this.setState({
loading: true
})
}
editApp = () => {
this.setState({
isAddModalVisible: true
})
}
}
when I run this code, tell me that:
TypeError: Cannot read properties of undefined (reading 'editApp')
What should I do to invoke this function in const columns? I tried to move the columns into the component but still did not work. This is my full code of this component:
import React, { Component } from 'react'
import CustomBreadcrumb from '#/components/CustomBreadcrumb'
import { Layout, Divider, Row, Col, Table, Button, notification, Form, message } from 'antd'
import '#/style/view-style/table.scss'
import { withRouter } from 'react-router-dom'
import { getAppList, addApp } from '#/service/global/AppService'
import moment from 'moment'
import AddApp from './crud/AddApp'
import EditApp from './crud/EditApp'
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id'
},
{
title: '应用名',
dataIndex: 'app_name',
key: 'app_name'
},
{
title: '应用编号',
dataIndex: 'app_id',
key: 'app_id'
},
{
title: '应用英文缩写',
dataIndex: 'app_abbr',
key: 'app_abbr'
},
{
title: '用户数',
dataIndex: 'user_count',
key: 'user_count'
},
{
title: '上线状态',
dataIndex: 'online_status',
key: 'online_status',
render: (text, record) => <span>{record.online_status === 1 ? '已上线' : '未上线'}</span>
},
{
title: '创建时间',
dataIndex: 'created_time',
key: 'created_time',
render: text => <span>{moment.unix(parseInt(text) / 1000).format('YYYY-MM-DD HH:mm:ss')}</span>
},
{
title: '备注',
dataIndex: 'remark',
key: 'remark'
},
{
title: '操作',
key: 'action',
render: (text, record) => (
<span>
<Button type='link'>详情</Button>
<Divider type='vertical' />
<Button onClick={this.editApp} type='link'>编辑</Button>
</span>
)
}
]
class App extends Component {
state = {
loading: false,
pageNum: 1,
pageSize: 10,
isAddModalVisible: false,
isEditModalVisible: true
}
enterLoading = () => {
this.setState({
loading: true
})
}
addApp = () => {
this.setState({
isAddModalVisible: true
})
}
editApp = () => {
this.setState({
isEditModalVisible: true
})
}
onPageChange = current => {
this.setState({
pageNum: current
})
let request = {
pageSize: this.state.pageSize,
pageNum: current
}
getAppList(request)
}
changePageSize(pageSize, current) {
this.setState({
pageSize: pageSize
})
let request = {
pageSize: pageSize,
pageNum: this.state.pageNum
}
getAppList(request)
}
onAddModalCancelClick = (rowData = {}) => {
const { isAddModalVisible } = this.state
this.setState({ isAddModalVisible: !isAddModalVisible })
}
onCreateApp = values => {
let params = {
appName: values.appName,
appAbbr: values.appAbbr
}
addApp(params)
}
componentDidMount() {
let request = {
pageSize: this.state.pageSize,
pageNum: this.state.pageNum
}
getAppList(request)
}
componentWillUnmount() {
notification.destroy()
this.timer && clearTimeout(this.timer)
}
render() {
let data = this.props.app.app.list
let apps = this.props.app.app
if ((data && Object.keys(data).length === 0) || data === undefined) {
return <div></div>
}
let total = parseInt(apps.pagination.total)
const paginationProps = {
showSizeChanger: true,
showQuickJumper: true,
pageSize: apps.pagination.pageSize,
pageSizeOptions: ['10', '20', '30'],
showTotal: () => `共${total}条`,
current: apps.pagination.pageNum,
total: total,
onShowSizeChange: (current, pageSize) => this.changePageSize(pageSize, current),
onChange: current => this.onPageChange(current)
}
return (
<Layout>
<div>
<CustomBreadcrumb arr={['应用', '全局', '应用']}></CustomBreadcrumb>
</div>
<Row>
<Col>
<div className='base-style'>
<h3 id='basic'>应用管理</h3>
<Divider />
<Button
type='primary'
onClick={this.addApp}
shape='round'
style={{ width: 90, marginRight: 8 }}>
添加应用
</Button>
<Table columns={columns} dataSource={data} pagination={paginationProps} rowKey='id' />
<AddApp
visible={this.state.isAddModalVisible}
onVisibleChange={this.onAddModalCancelClick}
onCreate={this.onCreateApp}
{...{ data }}
/>
<EditApp
visible={this.state.isEditModalVisible}
onVisibleChange={this.onAddModalCancelClick}
onCreate={this.onCreateApp}
{...{ data }}
/>
</div>
</Col>
</Row>
</Layout>
)
}
}
export default withRouter(App)
You can't access funtion outside its lexical scope
import React, { Component } from "react";
import CustomBreadcrumb from "#/components/CustomBreadcrumb";
import {
Layout,
Divider,
Row,
Col,
Table,
Button,
notification,
Form,
message,
} from "antd";
import "#/style/view-style/table.scss";
import { withRouter } from "react-router-dom";
import { getAppList, addApp } from "#/service/global/AppService";
import moment from "moment";
import AddApp from "./crud/AddApp";
import EditApp from "./crud/EditApp";
class App extends Component {
state = {
loading: false,
pageNum: 1,
pageSize: 10,
isAddModalVisible: false,
isEditModalVisible: true,
};
enterLoading = () => {
this.setState({
loading: true,
});
};
addApp = () => {
this.setState({
isAddModalVisible: true,
});
};
editApp = () => {
this.setState({
isEditModalVisible: true,
});
};
onPageChange = (current) => {
this.setState({
pageNum: current,
});
let request = {
pageSize: this.state.pageSize,
pageNum: current,
};
getAppList(request);
};
changePageSize(pageSize, current) {
this.setState({
pageSize: pageSize,
});
let request = {
pageSize: pageSize,
pageNum: this.state.pageNum,
};
getAppList(request);
}
onAddModalCancelClick = (rowData = {}) => {
const { isAddModalVisible } = this.state;
this.setState({ isAddModalVisible: !isAddModalVisible });
};
onCreateApp = (values) => {
let params = {
appName: values.appName,
appAbbr: values.appAbbr,
};
addApp(params);
};
componentDidMount() {
let request = {
pageSize: this.state.pageSize,
pageNum: this.state.pageNum,
};
getAppList(request);
}
componentWillUnmount() {
notification.destroy();
this.timer && clearTimeout(this.timer);
}
render() {
let data = this.props.app.app.list;
let apps = this.props.app.app;
if ((data && Object.keys(data).length === 0) || data === undefined) {
return <div></div>;
}
let total = parseInt(apps.pagination.total);
const paginationProps = {
showSizeChanger: true,
showQuickJumper: true,
pageSize: apps.pagination.pageSize,
pageSizeOptions: ["10", "20", "30"],
showTotal: () => `共${total}条`,
current: apps.pagination.pageNum,
total: total,
onShowSizeChange: (current, pageSize) =>
this.changePageSize(pageSize, current),
onChange: (current) => this.onPageChange(current),
};
const columns = [
{
title: "ID",
dataIndex: "id",
key: "id",
},
{
title: "应用名",
dataIndex: "app_name",
key: "app_name",
},
{
title: "应用编号",
dataIndex: "app_id",
key: "app_id",
},
{
title: "应用英文缩写",
dataIndex: "app_abbr",
key: "app_abbr",
},
{
title: "用户数",
dataIndex: "user_count",
key: "user_count",
},
{
title: "上线状态",
dataIndex: "online_status",
key: "online_status",
render: (text, record) => (
<span>{record.online_status === 1 ? "已上线" : "未上线"}</span>
),
},
{
title: "创建时间",
dataIndex: "created_time",
key: "created_time",
render: (text) => (
<span>
{moment.unix(parseInt(text) / 1000).format("YYYY-MM-DD HH:mm:ss")}
</span>
),
},
{
title: "备注",
dataIndex: "remark",
key: "remark",
},
{
title: "操作",
key: "action",
render: (text, record) => (
<span>
<Button type="link">详情</Button>
<Divider type="vertical" />
<Button onClick={this.editApp} type="link">
编辑
</Button>
</span>
),
},
];
return (
<Layout>
<div>
<CustomBreadcrumb arr={["应用", "全局", "应用"]}></CustomBreadcrumb>
</div>
<Row>
<Col>
<div className="base-style">
<h3 id="basic">应用管理</h3>
<Divider />
<Button
type="primary"
onClick={this.addApp}
shape="round"
style={{ width: 90, marginRight: 8 }}
>
添加应用
</Button>
<Table
columns={columns}
dataSource={data}
pagination={paginationProps}
rowKey="id"
/>
<AddApp
visible={this.state.isAddModalVisible}
onVisibleChange={this.onAddModalCancelClick}
onCreate={this.onCreateApp}
{...{ data }}
/>
<EditApp
visible={this.state.isEditModalVisible}
onVisibleChange={this.onAddModalCancelClick}
onCreate={this.onCreateApp}
{...{ data }}
/>
</div>
</Col>
</Row>
</Layout>
);
}
}
export default withRouter(App);
I used Ant table to show some information.
https://codesandbox.io/s/proud-architecture-lsb85?file=/src/index.js
I want to customize the position of the checkbox for row selection.
In this application, you can see the header in the following order of checkbox, Name, Age, Address but I want to swap checkbox and Name.
You can add checkbox columns and customize render and titleRender of it to checkbox and then handle the events. if you incounter performance issue you have to add some memoization on columns or evenet handlers.
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Table, Button, Checkbox } from "antd";
const data = [];
for (let i = 0; i < 46; i++) {
data.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`
});
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRowKeys: [], // Check here to configure the default column
loading: false,
allChecked: false
};
this.columns = [
{
title: "Name",
dataIndex: "name"
},
{
dataIndex: "checked",
title: () => {
return (
<Checkbox
checked={this.state.allChecked}
onChange={(e) => this.selectAll(e)}
></Checkbox>
);
},
render: (text, rec, index) => {
return (
<Checkbox
checked={
this.state.selectedRowKeys.includes(rec.key) ||
this.state.allChecked
}
onChange={(e) => this.onChange(e, rec)}
></Checkbox>
);
}
},
{
title: "Age",
dataIndex: "age"
},
{
title: "Address",
dataIndex: "address"
}
];
}
start = () => {
this.setState({ loading: true });
// ajax request after empty completing
setTimeout(() => {
this.setState({
selectedRowKeys: [],
loading: false
});
}, 1000);
};
onChange = (e, rec) => {
const checked = e.target.checked;
if (checked) {
this.setState((state) => ({
...state,
selectedRowKeys: [...state.selectedRowKeys, rec.key]
}));
} else {
this.setState((state) => ({
...state,
selectedRowKeys: [
...state.selectedRowKeys.filter((item) => item !== rec.key)
]
}));
}
};
selectAll = (e) => {
const checked = e.target.checked;
if (checked) {
this.setState((state) => ({
...state,
allChecked: true
}));
} else {
this.setState((state) => ({
...state,
allChecked: false
}));
}
};
onSelectChange = (selectedRowKeys) => {
console.log("selectedRowKeys changed: ", selectedRowKeys);
this.setState({ selectedRowKeys });
};
render() {
const { loading, selectedRowKeys } = this.state;
const hasSelected = selectedRowKeys.length > 0;
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={this.start}
disabled={!hasSelected}
loading={loading}
>
Reload
</Button>
<span style={{ marginLeft: 8 }}>
{hasSelected ? `Selected ${selectedRowKeys.length} items` : ""}
</span>
</div>
<Table columns={this.columns} dataSource={data} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
I need to increase or decrease state value in catalog > spec > units, if I click on increase button the number in units should increase by one and if I click on decrease button it should decrease by one, I'd tried by setting state in the render, but it didn't work and I think this is not a good practice. How can I create a function to setState of units without declaring it inside the render method?
Here is an example of my code:
export default class Order extends Component {
constructor(props) {
super(props);
this.state = {
catalog: [
{
photo: 'https://via.placeholder.com/400x400',
title: 'My title',
description: 'Bla bla bla...',
spec: { size: 'FAM', units: 1, price: 999999, id: 'CMB0', selectedIndicator: '', isSelected: false, name: 'A simple name' },
isCombo: true
},
],
}
}
}
render(){
return(
{this.state.catalog.map((item, index) => {
<div key={index}>
<strong>{item.title}</strong>
<span>{item.spec.units}</span>
<button onClick={() => item.spec.units + 1}>increase</button>
<button onClick={() => item.spec.units - 1}>decrease</button>
</div>})
}
)
}
Try this
increase = title => {
const newCatalogState = this.state.catalog.map(item => {
if (item.title === title) {
return {
...item,
spec: {
...item.spec,
units: item.spec.units + 1
}
};
}
return item;
});
this.setState({
catalog: newCatalogState
});
};
decrease = title => {
const newCatalogState = this.state.catalog.map(item => {
if (item.title === title) {
return {
...item,
spec: {
...item.spec,
units: item.spec.units - 1
}
};
}
return item;
});
this.setState({
catalog: newCatalogState
});
};
<button onClick={() => this.increase(item.title)}>increase</button>
<button onClick={() => this.decrease(item.title)}>decrease</button>
you can check here codesandbox hope it helps
Try this:
export default class Order extends Component {
constructor(props) {
super(props);
this.state = {
catalog: [
{
photo: 'https://via.placeholder.com/400x400',
title: 'My title',
description: 'Bla bla bla...',
spec: { size: 'FAM', units: 1, price: 999999, id: 'CMB0', selectedIndicator: '', isSelected: false, name: 'A simple name' },
isCombo: true
},
],
}
}
}
const updateUnits = (index, value) => {
const { catalog } = this.state
catalog[index].spec.units += value
this.setState({catalog})
}
render(){
return(
{ this.state.catalog.map((item, index) => {
<div key={index}>
<strong>{item.title}</strong>
<span>{item.spec.units}</span>
<button onClick={() => this.updateUnits(index, 1)}>increase</button>
<button onClick={() => this.updateUnits(index, -1)}>decrease</button>
</div>})
}
)
}
I'm creating a custom dropdown list, where a button (Trigger) plays the role as the dropdown's trigger. Here I'm trying to change the dropdown title into the name of any selected options. To do this, I store the new selected value in selectedOption and use them to replace the title. However receive an error of: Cannot read property 'label' of undefined.
How to resolve and make the dropdown works?
Really appreciate any enlightenment! Thank you
const Dropdown = props => {
const { onChange, label, disabled } = props;
const options = [
{ value: '0', label: 'All Flavour' },
{ value: '1', label: 'Strawberry' },
{ value: '2', label: 'Rum Raisin' },
{ value: '3', label: 'Hazelnut' },
{ value: '4', label: 'Chocochip' },
{ value: '5', label: 'Coffee' },
];
const [open, setOpen] = useState(false);
const handleTriggerClick = useCallback(() => setOpen(prev => !prev), []);
const handleChange = useCallback(
newValue => {
if (!disabled) {
onChange(newValue);
setOpen(false);
}
},
[onChange]
);
const selectedOption = options.find(option => option.label === label);
const displayMenu = open && !disabled;
return (
<>
<Container>
<OutletIcon />
<Trigger
disabled={disabled}
title={selectedOption.label || ''}
onClick={handleTriggerClick}
>
<TriggerText>{selectedOption.label || ''}</TriggerText>
<SortIcon />
</Trigger>
<DropdownMenu isDisplayed={displayMenu}>
{options.map(option => {
const isSelected = option.label === label;
const otherProps = {};
if (!isSelected) {
otherProps.onClick = () => handleChange(option.label);
}
return (
<DropdownMenuItem
key={option.value}
title={option.label}
selected={isSelected}
{...otherProps}
>
<DropdownMenuItemText onClick={handleTriggerClick}>
{option.label}
</DropdownMenuItemText>
<GreenCheckIcon />
</DropdownMenuItem>
);
})}
</DropdownMenu>
</Container>
</>
);
};
Hereby is the props declaration
Dropdown.defaultProps = {
disabled: false,
onChange: () => {},
label: '',
};
Dropdown.propTypes = {
disabled: PropTypes.bool,
onChange: PropTypes.func,
label: PropTypes.string,
};
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.