I have a specific problem in my React-Redux app. so I display rerender my component, when my this.state.boolean change value. A few lines of code express more than a thousand words:
Please look on my method appendTable setstate boolean to false, and when this end operations, setState boolean to true. I would like to rerender my component only then my boolean state changing state.
class TableComponent extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
columnStatic: [{ name: "customerName", title: "Client" }],
columnsDynamic: [],
columnBands: [],
columns: [],
tableColumnExtensions: [],
percentColumns: [],
boolean: true
};
this.handleDateWeek = this.handleDateWeek.bind(this);
this.appendTable = this.appendTable.bind(this);
this.Auth = new AuthService();
}
componentDidMount() {
this.handleDateWeek();
}
componentDidUpdate(prevProps) {
if (
this.props.isLoading === false &&
prevProps.isLoading !== this.props.isLoading
)
this.appendTable();
}
handleDateWeek() {
this.props.handleLastWeek(this.props.dateFrom, this.props.dateTo);
}
appendTable() {
this.setState(
{
columnStatic: [{ name: "customerName", title: "Klient" }],
columnsDynamic: [],
columnBands: [],
columns: [],
tableColumnExtensions: [],
percentColumns: [],
boolean: false
},
() => {
var i = 1;
var j = 1;
var k = 1;
var l = 0;
var dateArray = [];
this.props.dataApi.map(dA => {
dA.data.map(dat => {
if (dateArray.indexOf(dat.date) > -1) {
return;
}
dateArray.push(dat.date);
this.setState(prevState => ({
columnsDynamic: [
...prevState.columnsDynamic,
{ name: "ordersAmount" + i++, title: "Zamówienia" },
{ name: "earnings" + i++, title: "Obrót (brutto)" }
],
columnBands: [
...prevState.columnBands,
{
title: `${dat.date}`,
children: [
{ columnName: "ordersAmount" + j++ },
{ columnName: "earnings" + j++ }
]
}
],
percentColumns: [
...prevState.percentColumns,
`ordersAmount${l++ % 2 != 0 ? l : l++}`
],
tableColumnExtensions: [
...prevState.tableColumnExtensions,
{
columnName: "ordersAmount" + k++,
width: 90,
align: "right"
},
{
columnName: "earnings" + k++,
width: 150,
align: "right"
}
],
boolean: true
}));
});
});
}
);
}
...
return (
<Fragment>
<div className="tableContainerHead">
{this.props.isLoading ? (
<Loading />
) : (
<Fragment>
<Grid
rows={dataApi}
columns={columns.concat(columnStatic, columnsDynamic)}
>
<PercentTypeProvider for={percentColumns} />
...
);
You could add the method shouldComponentUpdate():
shouldComponentUpdate(nextProps, nextState) {
return (nextState.boolean !== this.state.boolean) ? true : false;
}
It should now re-render only when the boolean property has been updated.
I suggest you change the name of that property though, as Boolean is a reserved keyword and it is very close. Perhaps something more semantically descriptive?
Related
I am getting the following error
"TypeError: Cannot read property 'call' of undefined"
I am trying to store Axios get results into a variable and show it in MUI Datatable before render method, and I need to access these values in another class as well.
But when i try to set variable value in this.setState, it gives error and blank page shows up.
I am also binding method in the constructor.
Here is my code
export default class myList extends React.Component {
constructor(props) {
super(props);
this.componentDidMount = this.componentDidMount.bind(this);
this.state = { isLoading: true, myData: undefined };
}
componentDidMount() {
Axios.get(url).then(data => {
this.setState({ myData: data.data, isLoading: false });
});
}
render() {
const { isLoading, myData } = this.state;
if (isLoading) {
return <div className="myList">Loading...</div>;
}
const columns = [
{
name: 'id', // field name in the row object
label: 'ID', // column title that will be shown in table
options: {
display: false,
},
},
{
name: 'Name',
label: 'name',
options: {
display: false,
customBodyRender: (value) => {
return value === null ? "-" : value
},
},
},
{
label: "Actions",
name: "action",
options: {
customBodyRender: (value, tableMeta, updateValue) => {
return (
<Fragment>
<button style={{border: '0px', backgroundColor: 'white'}} onClick={() =>window.$cl_id =tableMeta.rowData[0] }>
</button> </Fragment>
)
}
}
},
]
return (
<React.Fragment>
<div className="myList">
<MUIDataTable
title={'My Data'}
data={myData }
columns={columns}
options={{
selectableRows: false, // set checkbox for each row
elevation: 0,
rowsPerPage: 10,
rowsPerPageOptions: [10, 20, 40, 80, 100],
}}
/>
</div>
</React.Fragment>
);
}
}
I have a select component defined like this:
this.state.list = [{label: "test1", value:1}, {label:"test2", value:2}, {label:"test3", value:3}]
this.state.selected = [{label:"test2", value:2}]
let listMap = this.state.list
let list = this.state.list
{listMap.length !== 0 ? listMap.map((item: any, key: number) => (
<div>
<Select
id="list for data"
options={list}
onChange={value => selectList(value)}
placeholder="Select Your Option"
/>
<div/>
))
I want is after test2 is selected, I want the other two drop downs to show test1, and test3.
What I have done so far:
let y = this.state.selected.map(itemY => { return itemY.value })
let x = list.filter(itemX => !yFilter.includes(itemX.value)) // [{value: 1, label:"test1"},{value: 3, label: "test3"}]
And then replacing options property as x.
The filters are working but,
The place holder is not updating the selected values.
What I want to achieve:
And for the next drop down [1], be only able to select those which aren't selected:
You have to separate the three react selects. As you are applying filter on one it will be applicable to all react select.The filtering will also remove in all react select. You can checkout following example.
https://codesandbox.io/s/react-select-5u3rh
import React from "react";
import {
render
} from "react-dom";
import ReactDOM from "react-dom";
import Select from "react-select";
import "react-select/dist/react-select.css";
class ReactSelect extends React.Component {
constructor(props) {
super(props);
this.state = {
itemtitle: "",
multi: true,
multiValue: "eeee...",
options: [{
value: "Color",
label: "Yellow"
},
{
value: "Fruit",
label: "Apple"
},
{
value: "Tool",
label: "Spanner"
}
],
options2: [{
value: "Color",
label: "Yellow"
},
{
value: "Fruit",
label: "Apple"
},
{
value: "Tool",
label: "Spanner"
}
]
};
}
onTitleChange(e, value) {
this.setState({
[e.target.name]: e.target.value
});
this.setState({
multiValue: e.target.value
});
}
handleOnChange(obj) {
this.setState({
multiValue: obj
});
this.setState({
options2: this.state.options2.filter(v => v.value !== obj.value)
})
}
handleOnChange2(obj) {
this.setState({
multiValue2: obj
});
}
render() {
return ( <
div >
<
Select
// multi={this.state.multi}
options = {
this.state.options
}
onChange = {
this.handleOnChange.bind(this)
}
value = {
this.state.multiValue
}
isSearchable = {
false
}
placeholder = "eee" /
>
<
Select
// multi={this.state.multi}
options = {
this.state.options2
}
onChange = {
this.handleOnChange2.bind(this)
}
value = {
this.state.multiValue2
}
isSearchable = {
false
}
placeholder = "eee" /
>
<
/div>
);
}
}
ReactDOM.render( < ReactSelect / > , document.body);
your state should look like this
state = { items : [{value: 1, label:"test1", selected:false},{value: 1, label:"test2", selected:false},{value: 3, label: "test3", selected:false}]
Then when an option is clicked, it sets the key "selected" to true. Afterward, only map the objects with selected false as dropdown items. Remember to use setState.
My end goal here is to do some very simple email validation and get my "next" button to disable or enable based on the validity of the email. I was testing my .isWorking() function (controls the boolean that is passed to the disabled attribute of the button) and when I test with email.length > 0, the function appears to work! But when I change it slightly to email.length > 4, the function does not work and just automatically returns "true", disabling the button. Any help at all would be appreciated--I am totally stuck on this and I would be so grateful!
const validEmailRegex = RegExp(/^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
class Signup extends React.Component {
constructor() {
super();
this.state = {email: ""};
this.handleSubmit = this.handleSubmit.bind(this);
}
isWorking (event) {
//testing function here
const email = event.target;
if (email.length > 4 ) {
return false;
}
return true;
//if (validEmailRegex.test(email) === true) {
// return false;
//}
//return true;
}
handleSubmit(event) {
event.preventDefault();
if (!event.target.checkValidity()) {
this.setState({ invalid: true, displayErrors: true,
});
return;
}
const form = event.target;
const data = new FormData(form);
for (let name of data.keys()) {
const input = form.elements[name];
const parserName = input.dataset.parse;
console.log('parser name is', parserName);
if (parserName) {
const parsedValue = inputParsers[parserName](data.get(name));
data.set(name, parsedValue);
}
}
this.setState({
res: stringifyFormData(data), invalid: false, displayErrors: false,
});
}
render() {
const { res, invalid, displayErrors } = this.state;
//pass boolean to the button for disabling or not
const isEnabled = this.isWorking(event);
return (
React.createElement("div", { className: "container" },
React.createElement("div", { className: "row" },
React.createElement("form", { onSubmit: this.handleSubmit, noValidate: true, className: displayErrors ? 'displayErrors' : '' },
React.createElement("input", { className: "form-control", name: "formEmail", id: "formEmail", type: "email", placeholder: "email"}),),
React.createElement("span", { className: "span"},
React.createElement("button", { className: "button1", disabled: isEnabled, type: "button"}, "next")
),));}}
class Signup extends React.Component {
constructor() {
super();
this.state = {email: "", isEnabled: true};
this.handleSubmit = this.handleSubmit.bind(this);
}
isWorking (event) {
//testing function here
const email = event.target.value;
console.log(email.length)
if (email.length > 4 ) {
this.setState({ isEnabled: false});
} else {
this.setState({ isEnabled: true});
}
}
handleSubmit(event) {
event.preventDefault();
if (!event.target.checkValidity()) {
this.setState({ invalid: true, displayErrors: true,
});
return;
}
const form = event.target;
const data = new FormData(form);
for (let name of data.keys()) {
const input = form.elements[name];
const parserName = input.dataset.parse;
console.log('parser name is', parserName);
if (parserName) {
const parsedValue = inputParsers[parserName](data.get(name));
data.set(name, parsedValue);
}
}
this.setState({
res: stringifyFormData(data), invalid: false, displayErrors: false,
});
}
render() {
const { res, invalid, displayErrors } = this.state;
//pass boolean to the button for disabling or not
// const isEnabled = this.isWorking(event);
return (
React.createElement("div", { className: "container" },
React.createElement("div", { className: "row" },
React.createElement("form", { onSubmit: this.handleSubmit, onChange:(e)=>this.isWorking(e), noValidate: true, className: displayErrors ? 'displayErrors' : '' },
React.createElement("input", { className: "form-control", name: "formEmail", id: "formEmail", type: "email", placeholder: "email"}),),
React.createElement("span", { className: "span"},
React.createElement("button", { className: "button1", disabled: this.state.isEnabled, type: "button"}, "next")
),)));}}
class Signup extends React.Component {
constructor() {
super();
this.state = { email: "", isEnabled: true };
this.isWorking = this.isWorking.bind(this);
}
isWorking(event) {
//testing function here
console.log("event", event.target.value);
const email = event.target.value;
if (email.length > 4) {
this.setState({ isEnabled: false });
} else {
this.setState({ isEnabled: true });
}
return true;
}
render() {
const { displayErrors } = this.state;
return React.createElement(
"div",
{ className: "container" },
React.createElement(
"div",
{ className: "row" },
React.createElement(
"form",
{
onSubmit: this.handleSubmit,
noValidate: true,
className: displayErrors ? "displayErrors" : ""
},
[
React.createElement("input", {
className: "form-control",
name: "formEmail",
id: "formEmail",
type: "email",
placeholder: "email",
onChange: this.isWorking
}),
React.createElement(
"span",
{ className: "span" },
React.createElement(
"button",
{
className: "button1",
disabled: this.state.isEnabled,
type: "button"
},
"next"
)
)
]
)
)
);
}
The following code works as expected when the variable 'works' is set to true (in chromium) but doesn't when it's not. I'm trying to figure out why. Although I can just use the working one, probably I should understand better why the non-working one doesn't work. Why should there be any difference between pushing array items one at a time with this.push and setting the entire array with this.set?
'use strict'
var data = [{
id: 1,
children: [{
id: 2
}, {
id: 3,
children: [{
id: 4
}, {
id: 5,
children: [{
id: 6
}, {
id: 7
}]
}, {
id: 8
}]
}, {
id: 9,
children: [{
id: 10,
children: [{
id: 11
}, {
id: 12
}, {
id: 13
}]
}, {
id: 14
}, {
id: 15
}]
}]
}];
class Polymerology2Element extends Polymer.Element {
static get is() {
return 'polymerology2-element';
}
static get properties() {
return {
nodeData: {
type: Array,
value: [],
notify: true
},
node: {
type: null,
value: null,
notify: true
}
};
}
isOdd(num) {
return num % 2;
}
addNodes() {
var works = true;
if (works) {
if (this.node !== null) {
var arr = [];
for (var i = 0; this.node !== undefined &&
this.node !== null && this.node.children !== undefined && i < this.node.children.length; i++) {
arr.push(this.node.children[i]);
}
setTimeout(() => {
this.set('nodeData', arr)
}, 0);
}
} else {
if (this.node !== null) {
for (var i = 0; this.node !== undefined &&
this.node !== null && this.node.children !== undefined && i < this.node.children.length; i++) {
setTimeout(() => {
this.push('nodeData', this.node.children[i])
}, 0);
}
}
}
}
constructor() {
super();
if (Polymerology2Element.instance === undefined) {
this.nodeData = data;
this.node = null;
Polymerology2Element.instance = 0;
} else
Polymerology2Element.instance += 1;
this.instance = Polymerology2Element.instance;
}
connectedCallback() {
super.connectedCallback();
this.addNodes();
}
}
window.customElements.define(Polymerology2Element.is, Polymerology2Element);
:host {
display: block;
}
<base href="https://polygit.org/polymer+polymer+v2.3.1/components/" />
<script src="webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="polymer/polymer.html" />
<polymerology2-element></polymerology2-element>
<dom-module id="polymerology2-element">
<template>
<ul>
<template is="dom-repeat" items="[[nodeData]]" as="item">
<template is="dom-if" if="{{isOdd(item.id)}}">
<li>Instance: {{instance}}, Node: {{item.id}} (odd)</li>
<polymerology2-element node="[[item]]"></polymerology2-element>
</template>
<template is="dom-if" if="{{!isOdd(item.id)}}">
<li>Instance: {{instance}}, Node: {{item.id}} (even)</li>
<polymerology2-element node="[[item]]"></polymerology2-element>
</template>
</template>
</ul>
</template>
</dom-module>
I'm currently working on an input with mask in react-native, however I'd like to avoid input of non-numeric characters. I did, however I'd like to avoid the behavior below:
enter image description here
'use strict';
import React, { Component, PropTypes } from 'react';
import { styles, cleanStyle, dirtyStyle } from './styles';
import { colors } from '../../config/styles';
import {
Animated,
Easing,
Platform,
StyleSheet,
Text,
TextInput,
View,
Keyboard,
} from 'react-native';
const textPropTypes = Text.propTypes || View.propTypes;
const textInputPropTypes = TextInput.propTypes || textPropTypes;
const propTypes = {
...textInputPropTypes,
inputStyle: textInputPropTypes.style,
labelStyle: textPropTypes.style,
disabled: PropTypes.bool,
style: View.propTypes.style,
};
const SMInput = React.createClass({
propTypes,
getDefaultProps() {
return {
editable: true,
onlyNumbers: false,
underlineColorAndroid: 'transparent'
};
},
getInitialState() {
Keyboard.addListener('keyboardDidChangeFrame', () => {
console.log('keyboardDidChangeFrame');
});
const state = {
text: (this.props.value) ? this.props.value.toString() : '',
dirty: !!this.props.value,
borderColor: new Animated.Value(0),
labelColor: new Animated.Value(0),
maxLength: this.props.maxLength,
placeHolder: '',
};
const style = state.dirty ? dirtyStyle : cleanStyle;
state.labelStyle = {
fontSize: new Animated.Value(style.fontSize),
top: new Animated.Value(style.top),
position: new Animated.Value(style.position),
}
return state;
},
_animate(dirty) {
const animateTime = 150;
const nextStyle = dirty ? dirtyStyle : cleanStyle;
const labelStyle = this.state.labelStyle;
const anims = Object.keys(nextStyle).map(prop => {
return Animated.timing(
labelStyle[prop],
{
toValue: nextStyle[prop],
duration: animateTime,
},
Easing.ease
)
});
setTimeout(() => {
if (this.props.placeholder && dirty) {
this.setState({
placeHolder: this.props.placeholder
});
}
}, 120);
anims.push(
Animated.timing (
this.state.borderColor, {
toValue: dirty ? 1 : 0,
duration: animateTime,
}
)
);
anims.push(
Animated.timing (
this.state.labelColor, {
toValue: dirty ? 1 : 0,
duration: animateTime,
}
)
);
Animated.parallel(anims).start();
},
_onFocus() {
this._animate(true);
this.setState({ dirty: true });
if (this.props.onFocus) {
this.props.onFocus(arguments);
}
},
_onBlur() {
if (!this.state.text) {
this._animate(false);
this.setState({ dirty: false });
}
if (this.props.onBlur) {
this.props.onBlur(arguments);
}
if (this.props.placeholder) {
this.setState({
placeHolder: ''
});
}
},
onChangeText(text) {
this.setMask(text);
if (this.props.onChangeText) {
this.props.onChangeText(text);
}
},
setMask(text) {
//function mask(inputName, mask) {
var mask = '00/00/0000';
this.setState({
maxLength: mask.length
});
var value = text;
var literalPattern = /[0\*]/;
var numberPattern = /[0-9]/;
var newValue = '';
for (var vId = 0, mId = 0 ; mId < mask.length ; ) {
if (mId >= value.length) {
break;
}
// Number expected but got a different value, store only the valid portion
if (mask[mId] == '0' && value[vId].match(numberPattern) == null) {
break;
}
// Found a literal
while (mask[mId].match(literalPattern) == null) {
if (value[vId] == mask[mId]) {
break;
}
newValue += mask[mId++];
}
newValue += value[vId++];
mId++;
}
this.setState({
text: newValue
})
},
updateText(event) {
const text = event.nativeEvent.text;
this.setState({ text })
if (this.props.onEndEditing) {
this.props.onEndEditing(event);
}
},
_renderLabel() {
const labelColor = this.state.labelColor.interpolate({
inputRange: [ 0, 1 ],
outputRange: [ colors.darkPurple50, colors.purple100 ]
});
return (
<View style={ styles.wrapper }>
<Animated.Text
ref='label'
style={ [this.state.labelStyle, styles.label, this.props.labelStyle, { color: labelColor } ] }
>
{this.props.children}
</Animated.Text>
</View>
)
},
render() {
const borderColor = this.state.borderColor.interpolate({
inputRange: [ 0, 1 ],
outputRange: [ colors.gray80, colors.purple100 ]
});
const props = {
autoCapitalize: this.props.autoCapitalize,
autoCorrect: this.props.autoCorrect,
autoFocus: this.props.autoFocus,
bufferDelay: this.props.bufferDelay,
clearButtonMode: this.props.clearButtonMode,
clearTextOnFocus: this.props.clearTextOnFocus,
controlled: this.props.controlled,
editable: this.props.editable,
enablesReturnKeyAutomatically: this.props.enablesReturnKeyAutomatically,
keyboardType: this.props.keyboardType,
multiline: this.props.multiline,
onBlur: this._onBlur,
onChange: this.props.onChange,
onChangeText: this.onChangeText,
onEndEditing: this.updateText,
onFocus: this._onFocus,
onSubmitEditing: this.props.onSubmitEditing,
password: this.props.password,
returnKeyType: this.props.returnKeyType,
selectTextOnFocus: this.props.selectTextOnFocus,
selectionState: this.props.selectionState,
style: [styles.input],
maxLength: this.state.maxLength,
underlineColorAndroid: this.props.underlineColorAndroid, // android TextInput will show the default bottom border
onKeyPress: this.props.onKeyPress,
spellCheck: this.props.spellCheck,
mask: this.props.mask,
placeholder: this.state.placeHolder,
placeholderTextColor: colors.darkPurple50,
value: this.state.text,
};
const elementStyles = [styles.element];
if (this.props.inputStyle) {
props.style.push(this.props.inputStyle);
}
if (this.props.style) {
elementStyles.push(this.props.style);
}
if (!this.props.editable) {
elementStyles.push(styles.elementNotEditable);
props.style.push(styles.inputNotEditable);
}
return (
<Animated.View style={ [elementStyles, { borderColor: borderColor }] }>
{ this._renderLabel() }
<TextInput
{ ...props }
>
</TextInput>
</Animated.View>
);
},
});
SMInput.propTypes = {
disabled: PropTypes.bool,
style: Text.propTypes.style,
};
export default SMInput;