I'm using react-vis to make a line chart. I have a parent component called RoomUtilisation and children called ChartGridLine. The parent fetch data (currently using mock data), then pass it into children via props. However, somehow the chart only render when I change the dropdown list several time. The children component also uses a wrong set of data sometimes e.g. selected class A but uses data for class B.
I tried debugging and it seems that nextProps and prevState is the same in some instances. Please help!
var dataArrayA = [];
var dataArrayB = [];
for (var item in sampleDataWeek) {
dataArrayA.push([
sampleDataWeek[item].week,
sampleDataWeek[item].occupancy,
sampleDataWeek[item].capacity
]);
}
for (var item in sampleDataWeekB) {
dataArrayB.push([
sampleDataWeekB[item].week,
sampleDataWeekB[item].occupancy,
sampleDataWeekB[item].capacity
]);
}
class RoomUltilisation extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
loading: true,
selectedClass: "LectureA",
selectedCourse: "COMP9517",
counter: 0 //dummy prop
};
this.classOptions = [
{ value: 0, label: "LectureA" },
{ value: 1, label: "LectureB" }
];
this.courseOptions = [
{ value: 0, label: "COMP9517" },
{ value: 1, label: "ARTS2663" }
];
this.handleChange = this.handleChange.bind(this);
this.addData = this.addData.bind(this);
}
componentDidMount() {
if (this.state.selectedClass === "LectureA") {
this.setState({
data: dataArrayA
});
}
this.setState({
loading: false
});
}
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
});
if (this.state.selectedClass === "LectureA") {
this.setState({
data: dataArrayA
});
} else if (this.state.selectedClass === "LectureB") {
this.setState({
data: dataArrayB
});
}
};
render() {
const { loading } = this.state;
if (loading) {
return (
<React.Fragment>
<NavBar />
<SideBar />
<div id="page-wrap">
<h1 style={{ padding: 20 }}>Class Attendance</h1>
<div>Loading Chart ....</div>
</div>
</React.Fragment>
);
}
return (
<React.Fragment>
<NavBar />
<SideBar />
<div id="page-wrap">
<h1 style={{ padding: 20 }}>Class Attendance</h1>
<label htmlFor="course" style={this.textAreaStyle}>
Select course
</label>
<select
id="selectedCourse"
value={this.state.selectedCourse ? this.state.selectedCourse : ""}
onChange={this.handleChange}
>
{this.courseOptions.map((e, key) => {
return (
<option key={key} value={e.label}>
{e.label}
</option>
);
})}
</select>
<label htmlFor="class" style={this.textAreaStyle}>
Select class
</label>
<select
id="selectedClass"
value={this.state.selectedClass ? this.state.selectedClass : ""}
onChange={this.handleChange}
>
{this.classOptions.map((e, key) => {
return (
<option key={key} value={e.label}>
{e.label}
</option>
);
})}
</select>
<div id="chart-wrap">
<ChartGridline
data={this.state.data}
// key={++this.state.counter}
/>
</div>
</div>
</React.Fragment>
);
}
}
export default RoomUltilisation;
class ChartGridline extends Component {
constructor(props) {
super(props);
this.state = {
highlightSeries: null,
highlightTip: null,
receivedData: null,
loading: true,
data: null,
value: null //value of mark?
};
this.translatedArray = [];
this.debouncedSetState = debounce(newState => this.setState(newState), 40);
this._rememberValue = this._rememberValue.bind(this);
this._forgetValue = this._forgetValue.bind(this);
}
async componentDidMount() {
await this.translateSeries(this.props.data);
this.setState({ loading: false });
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.data !== prevState.data) {
return {
data: nextProps.data
};
}
// Return null if the state hasn't changed
return null;
}
async componentDidUpdate(prevProps, prevState, snapshot) {
if (JSON.stringify(this.props) !== JSON.stringify(prevProps.data)) {
console.log("state has changed!");
await this.translateSeries(this.props.data);
}
// if (snapshot.loading) {
// console.log("computing....!");
// }
}
async translateSeries(data) {
this.translatedArray = [1].map(i =>
data.map(input => ({
x: new Date(input[0]),
y: input[1],
capacity: input[2]
}))
);
console.log("translated function: " + JSON.stringify(this.translatedArray));
}
_rememberValue(value) {
this.setState({ value });
}
_forgetValue() {
this.setState({ value: null });
}
axisProps = {
tickSizeInner: 0,
style: { line: { stroke: "#939393", strokeWidth: "1px" } }
};
hintStyle = {
fontSize: 14,
color: "black",
background: "#faffe6",
borderRadius: "5px",
border: "3px solid #fff"
};
render() {
const { highlightSeries, loading, value } = this.state;
console.log("render method is called");
if (loading) {
return (
<React.Fragment>
<div>loading...</div>
</React.Fragment>
);
}
return (
<div>
<DiscreteColorLegend
// items={["Attendance", "Enrolment"]}
items={["Attendance"]}
orientation="horizontal"
// style={{ position: "absolute", textAlign: "left", right: "25%" }}
strokeWidth="3px"
/>
<XYPlot
xDomain={[0, 20]}
key="1"
width={600}
height={600}
onMouseLeave={() => this.setState({ highlightTip: null })}
>
<XAxis
title="semester week"
{...this.axisProps}
tickFormat={String}
/>
<YAxis
title="occupancy"
{...this.axisProps}
// tickFormat={d => d + "%"}
tickFormat={d => d}
/>
{this.translatedArray.map((d, i) => (
<LineMarkSeries
key={i}
size={3}
data={d}
onValueMouseOver={this._rememberValue}
onValueMouseOut={this._forgetValue}
onSeriesMouseOver={() =>
this.debouncedSetState({ highlightSeries: d })
}
onSeriesMouseOut={() =>
this.debouncedSetState({
highlightSeries: null
})
}
stroke={d === highlightSeries ? "black" : bgColors.Blue}
/>
))}
{console.log("this.translatedArray: " + this.translatedArray)}
{value ? (
<Hint value={value} style={this.hintStyle}>
<HintContent value={value} />
</Hint>
) : null}
</XYPlot>
</div>
);
}
}
export default ChartGridline;
Hi based on given code i can understand that you state value is not changing properly please change your handleChange method as follows:
handleChange = event => {
this.setState({
[event.target.id]: event.target.value
},() => {});
if (this.state.selectedClass === "LectureA") {
this.setState({
data: dataArrayA
},() => {});
} else if (this.state.selectedClass === "LectureB") {
this.setState({
data: dataArrayB
},() => {});
}
};
Related
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 find myself struggling to change the form input value from the button onClick handler. My problem is escalated by the fact that I have the line items on a form and things become even more complex that way. I tried to bring in a ref to set value,,, the value is displayed but at the form state after submission it remains empty which means the value is not being set. Below are all my code files. May someone kindly help me on where I may be missing the point.
class VehicleTemplate extends React.Component {
constructor(props){
super(props);
this.ws = new WebSocket('ws://localhost:8000/ws/weightData/');
this.socketRef = null;
this.state = {
data: 0,
name: '',
model: '',
plate_number: '',
type: 'truck',
wagons: [{ index: uuid(), label: '', type: 'once', weight: '' }],
total: 0,
};
this.onSubmit = this.onSubmit.bind(this);
this.handleChange= this.handleChange.bind(this);
this.handleChangeTable = this.handleChangeTable.bind(this);
this.addNewRow = this.addNewRow.bind(this);
this.deleteRow = this.deleteRow.bind(this);
this.handleLineItemChange = this.handleLineItemChange.bind(this);
}
componentDidMount() {
this.ws.onopen = () => {
// on connecting, do nothing but log it to the console
console.log('connected')
}
this.ws.onmessage = evt => {
// listen to data sent from the websocket server
// const message = JSON.parse(evt.data)
const {data} = this.state;
this.setState({data: evt.data})
// this.setState({this.state.lines.weight: data})
}
this.ws.onclose = () => {
console.log('disconnected')
// automatically try to reconnect on connection loss
}
};
onSubmit = (e) => {
e.preventDefault();
const {
name,
model,
plate_number,
type,
wagons,
} = this.state;
const vehicle = {
name,
model,
plate_number,
type,
wagons,
};
this.props.addVehicle(vehicle, this.props.token);
console.log(vehicle);
this.setState({
name: '',
model: '',
plate_number: '',
wagons: [],
});
};
handleLineItemChange = (elementIndex) => (event) => {
let wagons = this.state.wagons.map((item, i) => {
if (elementIndex !== i) return item
return {...item, [event.target.name]: event.target.value}
})
this.setState({wagons})
}
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
handleChangeTable = (name, id) => event => {
this.updateItem(id, { [name]: event.target.value });
};
addNewRow = (event) => {
this.setState({
wagons: this.state.wagons.concat(
[{index: uuid(), label: '', type: 'once', weight: '' }]
)
})
}
deleteRow = (index) => (event) => {
this.setState({
wagons: this.state.wagons.filter((item, i) => {
return index !== i
})
})
}
handleReorderLineItems = (newLineItems) => {
this.setState({
wagons: newLineItems,
})
}
clickOnDelete(record) {
this.setState({
wagons: this.state.lines.filter(r => r !== record)
});
}
render() {
const { classes } = this.props;
const {
data,
name,
model,
plate_number,
wagons,
} = this.state;
return (
<InformationTechnologyLayout>
<PapperBlock title="ADD VEHICLE" icon="ios-document-outline" desc="VEHICLE">
<Form>
<div style={{ clear: 'both' }} />
<h1>WEIGHT: {data}KG</h1>
<Grid container>
<Grid item xs={6}>
<Controls.Input
name="name"
label="Name"
value={name}
onChange={this.handleChange('name')}
/>
<Controls.Input
name="model"
label="MODEL"
value={model}
onChange={this.handleChange('model')}
/>
</Grid>
<Grid item xs={6}>
<Controls.Input
name="plate_number"
label="PLATE NUMBER"
value={plate_number}
onChange={this.handleChange('plate_number')}
/>
</Grid>
</Grid>
<Extensions
items={wagons}
addHandler={this.addNewRow}
changeHandler={this.handleLineItemChange}
focusHandler={this.handleFocusSelect}
deleteHandler={this.deleteRow}
reorderHandler={this.handleReorderLineItems}
data ={data}
/>
<div className='valueTable'>
<div className='row'>
<div className='label'>Subtotal</div>
<div className='value'>{this.calcLineItemsTotal()}KG</div>
</div>
<div className='row'>
<div className='label'>Total Due</div>
<div className='value'>{this.calcGrandTotal()}KG</div>
</div>
</div>
<Button variant="contained" onClick={this.onSubmit}>SUBMIT</Button>
</Form>
</PapperBlock>
</InformationTechnologyLayout>
);
}
}
On top is the main form component which has got Vehicle exetnsions and I am getting my weight from a websocket connection streaming scale outputs.
class Extensions extends Component {
handleDragEnd = (result) => {
if (!result.destination) return
// helper function to reorder result (src: react-beautiful-dnd docs)
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}
// perform reorder
const lineItems = reorder(
this.props.items,
result.source.index,
result.destination.index
)
// call parent handler with new state representation
this.props.reorderHandler(lineItems)
}
render = () => {
const {
items,
addHandler,
changeHandler,
focusHandler,
deleteHandler,
reorderHandler,
products,
data,
readOnly,
} = this.props
return (
<form>
<div className='lineItems'>
<div className='gridTable'>
<DragDropContext onDragEnd={this.handleDragEnd}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div
ref={provided.innerRef}
className= 'listDraggingOver'
>
{this.props.items.map((item, i) => (
<Draggable key={item.index} draggableId={item.index} index={i}>
{(provided, snapshot) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={provided.draggableProps.style}
className='listItemDragging'
>
<Extension
addHandler={addHandler}
changeHandler={changeHandler}
focusHandler={focusHandler}
deleteHandler={deleteHandler}
reorderHandler={reorderHandler}
data={data}
style={{color: 'red'}}
key={i + item.index}
index={i}
name={item.index}
label={item.label}
weight={item.weight}
/>
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
</div>
<div className='addItem'>
<button type="button" onClick={addHandler}><AddIcon size="1.25em" className='addIcon' /> Add Item</button>
</div>
</div>
</form>
)
}
}
This are the extensions and the last file is where I would like to capture weight from
class LineItem extends Component {
constructor(props){
super(props);
this.ref = React.createRef();
this.state = {
buttonState: false,
};
}
requestWeight = () => {
const { weight } = this.props;
const {buttonState} =this.state;
this.ref.current.value = this.props.data;
this.setState({
buttonState: true
})
};
render = () => {
const { index, label, weight } = this.props;
const {buttonState} = this.state;
return (
<div className='lineItem'>
<div>{index + 1}</div>
<Controls.Input
name="label"
label="LABEL"
value={label}
onChange={this.props.changeHandler(index)}
/>
<input
className='currency'
type='number'
readOnly={true}
ref={this.ref}
name='weight'
onChange={this.props.changeHandler(index)}
/>
<div>
<button type="button"
className='requestItems'
onClick={this.requestWeight}
disabled={buttonState}
>REQUEST WEIGHT</button>
</div>
<div>
<button type="button"
className='deleteItem'
onClick={this.props.deleteHandler(index)}
><DeleteIcon size="1.25em" /></button>
</div>
</div>
)
}
}
export default LineItem
If I add the value and put weight on the input then the ref stops working. I assume I might be missing something between my handleChange function and the requestWeight function but I really dont know what exaclty
I am loading a child component on parent component in React.js. With a click on the button, data will be pass to child component through props, and child component will map through that data and render on screen. I am getting data from localstorage and processing its data structure to child component.
But, the issue is when I click on the button and data is being passed and rendered, the button is shown and after the child component is rendered that shows up. I need the loading spinner when I click on the button and it disappears and shows the actual component.
I have tried methods like loading: false in the state but to no avail.
Thanks for your help
import ShowPatientAppointments from './ShowPatientAppointments.component';
class PatientAppointmnent extends Component {
state = {
doctorSlots: null,
timingSlot: null,
bookDay: null,
bookTime: null,
hasTiming: false,
}
getSlots = () => {
let slot = [];
let time = [];
for (let i=0; i< localStorage.length; i++) {
let key = localStorage.key(i);
let value = JSON.parse(localStorage[key]);
slot.push(key);
time.push(value);
this.setState({doctorSlots: slot, timingSlot: time});
}
console.log(this.state.doctorSlots, this.state.timingSlot);
}
render() {
const { doctorSlots, timingSlot, hasTiming } = this.state;
return(
<div>
<button onClick={this.getSlots} className='button'>Show me dates</button>
{doctorSlots === null ? <p></p> : <PatientSelectDay props={doctorSlots} timing={timingSlot} getTimings={this.getTiming} />}
</div>
)
}
}
export default PatientAppointmnent;
class PatientSelectDay extends Component {
state = {
options: [...this.props.props].map(obj => {
return {value: `${obj}`, label: `${obj}`}
}),
timingOptions: [...this.props.timing],
open_id: [],
part_id: '',
doctorDay: 'day',
doctorTiming: 'timing',
}
changeSingleHandler = e => {
this.setState({ part_id: e ? e.value : '' });
};
changeHandler = e => {
let add = this.state.open_id;
add.push(e.map(x => x.value));
this.setState({ open_id: e ? add : [] });
};
saveState = (option) => {
...save selected options
}
render() {
const {options, timingOptions} = this.state;
return (
<div>
<div className='carousel'>
{options.map((option, index) => {
const timing = timingOptions[index].map(obj => {
return {value: `${obj}`, label: `${obj}`}});
return(
<div key={index}>
<Select
name="open_id"
value={option}
onChange={this.changeSingleHandler}
options={option}
className='select'
/>
<Select
name="open_id"
value={this.state.open_id}
onChange={this.changeHandler}
options={timing}
className='select'
/>
<button onClick={() => this.saveState(option)} className='button-left'>Select Days</button>
</div>
)
})}
</div>
</div>
)
}
}
export default PatientSelectDay;
You need to update your code adding a loading state variable.
class PatientAppointmnent extends Component {
state = {
doctorSlots: null,
timingSlot: null,
bookDay: null,
bookTime: null,
hasTiming: false,
loading: false
}
getSlots = () => {
let slot = [];
let time = [];
this.setState({
loading: true
})
for (let i=0; i< localStorage.length; i++) {
let key = localStorage.key(i);
let value = JSON.parse(localStorage[key]);
slot.push(key);
time.push(value);
this.setState({doctorSlots: slot, timingSlot: time, loading: false});
}
console.log(this.state.doctorSlots, this.state.timingSlot);
}
renderButton = () => {
const { doctorSlots, timingSlot, loading } = this.state;
if(doctorSlots === null && timingSlot === null) {
return <div>
{loading ? <p>Loading...</p> : <button onClick={this.getSlots} className='button'>Show me dates</button>}
</div>
}
return null;
}
render() {
const { doctorSlots, timingSlot, hasTiming, loading } = this.state;
return(
<div>
{this.renderButton()}
{doctorSlots === null ? <p></p> : <PatientSelectDay props={doctorSlots} timing={timingSlot} getTimings={this.getTiming} />}
</div>
)
}
}
export default PatientAppointmnent;
class PatientSelectDay extends Component {
state = {
options: [...this.props.props].map(obj => {
return {value: `${obj}`, label: `${obj}`}
}),
timingOptions: [...this.props.timing],
open_id: [],
part_id: '',
doctorDay: 'day',
doctorTiming: 'timing',
}
changeSingleHandler = e => {
this.setState({ part_id: e ? e.value : '' });
};
changeHandler = e => {
let add = this.state.open_id;
add.push(e.map(x => x.value));
this.setState({ open_id: e ? add : [] });
};
saveState = (option) => {
...save selected options
}
render() {
const {options, timingOptions} = this.state;
return (
<div>
<div className='carousel'>
{options.map((option, index) => {
const timing = timingOptions[index].map(obj => {
return {value: `${obj}`, label: `${obj}`}});
return(
<div key={index}>
<Select
name="open_id"
value={option}
onChange={this.changeSingleHandler}
options={option}
className='select'
/>
<Select
name="open_id"
value={this.state.open_id}
onChange={this.changeHandler}
options={timing}
className='select'
/>
<button onClick={() => this.saveState(option)} className='button-left'>Select Days</button>
</div>
)
})}
</div>
</div>
)
}
}
export default PatientSelectDay;
I'm using react and react table. In my react table, I have a custom filter component which user can choose from the dropdown which filters he will use for the column. It's like less than, equal to, etc.
here I found some example and tried to make the same: https://codesandbox.io/s/03403m5xzp
everything works well when I'm using client side filtering but when using server-side data, there I get some problem.
problem is an example. I choose from dropdown some filter type like equal-to and open the input for typing. When the user types something I make a request with the onFetchData method for sending this filter values to backend API to getting new data and setting it to the table. When I got new data I change my state and of course, changing state of my filterComponent and user need to choose again the filter type and open the input for typing again.
what I can do for keeping the state of my filter component in the last state while table data change?
here is my react table and filterComponent code.
class ParentComponent extends Component {
state = {
betweens: false,
openTextBoxes: false
};
constructor() {
super();
this.state = {
pageSize: 15,
data: [],
pages: null,
loading: false
};
}
render() {
const { data, pages, loading } = this.state;
return (
<ReactTable
className="-striped -highlight"
data={this.state.data}
loading={this.state.loading}
manual
columns={columns}
pages={this.state.pages}
onFetchData={(state, instance) => {
this.setState({ loading: true });
let dataM = {
pagesize: state.pageSize,
page: state.page,
sorts: JSON.stringify(state.sorted),
filters: JSON.stringify(state.filtered)
};
axios
.post(baseUrl + "v1/report/data/list", dataM, {
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
})
.then(response => {
this.setState({
data: response.data.result,
pages: Math.ceil(
response.data.record_count / this.state.pageSize
),
loading: false
});
console.log(this.state.data);
})
.catch(error => {
throw error;
});
}}
filterable={true}
resizable={true}
sortable={true}
defaultFilterMethod={filterCaseInsensitive}
defaultPageSize={15}
pageSizeOptions={[5, 10, 15, 20, 25, 50, 100]}
getTdProps={onRowClick}
minRows={undefined}
/>
);
}
}
class FilterInnerComponent extends React.Component {
state = {
betweens: false
};
constructor(props) {
super(props);
this.state = {
filterType: "All",
filterValue: "",
filterBetweenValue: "",
openTextBox: true
};
this.changeFilterValue = this.changeFilterValue.bind(this);
}
changeFilterType(event) {
console.log(event);
// console.log(this.props.saveLastStateState)
const filterType = event.target.value;
selectedFilterTypeGlobal = filterType;
this.setState({ filterType: filterType });
const newValue = "";
this.state.filterValue = newValue;
this.state.filterBetweenValue = newValue;
const newState = {
...this.state.filterType,
...this.state.filterValue,
...this.state.filterBetweenValue,
filterType
};
if (filterType === "is-between" || filterType === "is-not-between") {
this.state.betweens = true;
} else {
this.state.betweens = false;
}
if (filterType !== "All") {
// this.props.getFilterinnerComponent()
// this.state.openTextBox = true
this.setState({
openTextBox: true
});
} else {
this.setState({
openTextBox: true
});
}
this.setState(newState);
this.props.onChange(newState);
}
changeFilterValue(event) {
const filterValue = event.target.value;
selectedFilterValueGlobal = filterValue;
parseFloat(filterValue).toFixed(2);
const newState = {
...this.state,
filterValue
};
this.setState(newState);
this.props.onChange(newState);
}
changeBetweenFilterValue(event) {
if (event.keyCode === 13) {
}
const filterBetweenValue = event.target.value;
parseFloat(filterBetweenValue).toFixed(2);
const newState = {
...this.state,
filterBetweenValue
};
// Update local state
this.setState(newState);
// Fire the callback to alert React-Table of the new filter
this.props.onChange(newState);
}
render() {
return (
<div className="filter">
<SelectField
onChange={evt => this.changeFilterType(evt)}
style={{
height: "30px",
fontSize: "12px"
}}
value={this.state.filterType}
autoWidth
>
<MenuItem value="All">All</MenuItem>
<MenuItem value="is-equal-to">Is Equal To</MenuItem>
<MenuItem value="is-not-equal-to">Is Not Equal To</MenuItem>
<MenuItem value="greater-than">Greater Than</MenuItem>
<MenuItem value="greater-than-or-equal-to">
Greater Than Or Equal To
</MenuItem>
<MenuItem value="less-than">Less Than</MenuItem>
<MenuItem value="less-than-or-equal-to">
Less Than Or Equal To
</MenuItem>
<MenuItem value="is-between">Is Between</MenuItem>
<MenuItem value="is-not-between">Is Not Between</MenuItem>
</SelectField>
{this.state.openTextBox ? (
<TextField
onChange={this.changeFilterValue}
style={{
width: "100%",
height: "40px",
float: "left",
fontSize: "12px"
}}
type="text"
value={this.state.filterValue}
/>
) : null}
{this.state.betweens ? (
<TextField
onChange={evt => this.changeBetweenFilterValue(evt)}
style={{
width: "100%",
height: "40px",
float: "left",
fontSize: "12px"
}}
type="text"
value={this.state.filterBetweenValue}
/>
) : null}
</div>
);
}
}
componentDidMount() {
const restaurants = Restaurant.all()
restaurants.then( rests => {
this.setState({
restaurants: rests
})
})
}
render() {
const { restaurants } = this.state;
return (
<main className="SearchRestaurantsPage" style={{textAlign: 'center'}}>
<Chosen className="Chosen-select" onChange={ value => console.log(value) }>
{
restaurants.map( restaurant => {
return restaurant ?
( <option key={restaurant.id}>{ restaurant.name }</option> )
:
''
})
}
</Chosen>
</main>
);
}
I have my react code above and trying to return a mapped array that is supposed to be something like
[<option key={1}>first</option>, <option key={2}>two</option>, <option key={3}>three</option>]
It works if I put a randomly created array like this,
render() {
const { restaurants } = this.state;
return (
<main className="SearchRestaurantsPage" style={{textAlign: 'center'}}>
<Chosen className="Chosen-select" onChange={ value => console.log(value) }>
{
[<option key={1}>first</option>, <option key={2}>two</option>, <option key={3}>three</option>]
}
</Chosen>
</main>
);
}
but no matter what I do with the map method, it just doesn't show anything.
I have already checked there is an array containing elements assigned to this.state.restaurant.
componentDidMount is called after the first render. Consequently your restaurants is undefined when the first render processed.
You can check if restaurants exists in render method:
componentDidMount() {
const restaurants = Restaurant.all()
restaurants.then( rests => {
this.setState({
restaurants: rests
})
})
}
render() {
const { restaurants } = this.state;
return (
<main className="SearchRestaurantsPage" style={{textAlign: 'center'}}>
<Chosen className="Chosen-select" onChange={ value => console.log(value) }>
{
restaurants && restaurants.map( restaurant => {
return restaurant ?
( <option key={restaurant.id}>{ restaurant.name }</option> )
:
null
})
}
</Chosen>
</main>
);
}
Also, check if your state is defined in the constructor or as the class property.
So the whole component could be the follow:
class Rests extends React.Component {
state = {restaurants: null};
componentDidMount() {
const restaurants = Restaurant.all()
restaurants.then( rests => {
this.setState({
restaurants: rests
})
})
}
render() {
const { restaurants } = this.state;
if (!restaurants) {
return null; // or you can return <LoadingSpinner /> here
}
return (
<main className="SearchRestaurantsPage" style={{textAlign: 'center'}}>
<Chosen className="Chosen-select" onChange={ value => console.log(value) }>
{
restaurants.map( restaurant => {
return restaurant ?
( <option key={restaurant.id}>{ restaurant.name }</option> )
:
null
})
}
</Chosen>
</main>
);
}
}
In the last example, we render nothing if there is no any data in restaurants. After we fetch data we rerender component and show options to users
The issue might be where you declared the restaurent constant from the state. I've written a sample code that works below.
import React from 'react';
const restaurentData = [
{
id: 1,
name: 'name 1'
},
{
id: 2,
name: 'name 2'
},
{
id: 3,
name: 'name 3'
}
]
class Hello extends React.Component {
constructor() {
super();
this.state = {
restaurents: restaurentData
}
}
render () {
const restaurents = this.state.restaurents;
return (
<ul>
{restaurents.map(restaurent => {
return restaurent
? (<li key={restaurent.id}>{`${restaurent.id} -- ${restaurent.name}`} </li>)
: null;
})}
</ul>
)
}
}
export default Hello;