React: Unable to change value by a function in setState - reactjs

I am trying to copy a value in state objects first and second through a function in setState, but the values are being changed in the object value, but not in first or second.
const InitVal = ({ strValue, handleClick }) => (
<div>
{strValue.map((item) => (
<button onClick={() => handleClick(item.key)}>{item.key}</button>
))}
</div>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {strValue: [{ key: '7' },{ key: '8' },{ key: '9' },{ key: '4' },{ key: '5' },{ key: '6' },{ key: '1' },{ key: '2' },{ key: '3' },{ key: '0' },{key: '+'},{key: '-'} ],value: '0',auxStr: '0',first: '',second: ''};
this.handleClick = this.handleClick.bind(this);
}
handleClick(key) {
const { value, auxStr, first, second } = this.state;
const digNprd = /[0-9]/;
if (digNprd.test(key)) {
this.setState({ value: `${value}${key}`, auxStr: `${auxStr}${key}`} );
} else if (key === '+') {
this.setState({ value: ` ${auxStr} on `, function(auxStr) { return { first: `${auxStr}`} } })
} else if (key === '-') {
this.setState({ value: ` ${auxStr} off `, function() { return { second: `${auxStr}`} } })
}
}
render() {
return (
<div><br /><InitVal strValue={this.state.strValue} handleClick={this.handleClick} /> <br /> {" "}
<br />{" "}
<div>value: {this.state.value}</div>
<br />
<div>AuxStr: {this.state.value}</div>
<br />
<div>First: {this.state.first}</div>
<br />
<div>Second: {this.state.second}</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));

You shouldn't add anonymous functions to your JavaScript classes, instead declare your functions/methods in the body of the class.
Take a look at this How to use anonymous functions in ES6 class.
But if you wish to play around how to manage to set those first & second values with functions as you started in your codesandbox, you can use something like this with IIFE:
...(function () {
return { second: `${auxStr}` };
})()
And again, you simply can do:
first: `${auxStr}`, second: `${auxStr}`
Edit: codesandbox

Try using arrow function
Like this
handleClick = (key) => { }

Related

DataSearch component executes search every time a key is pressed

So I'm trying to make the DataSearch component behave but the component calls the search/triggerquery for every key stroke and I don't understand why. Also javascript throws an exception because it want's the dataField attribute defined even though I'm making use of a customQuery. I only want the query to be called, when the user presses enter. Can anyone help?
class DocumentSearchComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: "",
corpus: "xxxx",
url: "http://localhost:7777",
};
this.handleKey = this.handleKey.bind(this);
this.onChange = this.onChange.bind(this);
}
handleKey(e, triggerQuery) {
if (e.key === "Enter") {
triggerQuery();
}
};
onChange(value) {
this.setState({
value,
});
};
customQuery(test) {
return {
query: {...}
},
_source: ["title", "publicationDate"],
size: 10,
highlight: {
pre_tags: ['<em>'],
post_tags: ['</em>'],
fields: {
fullText: {}
}
}
}
}
render() {
return (
<div className="App">
<ReactiveBase app={this.state.corpus} url={this.state.url}>
<DataSearch
componentId="documentSearch"
className="search-bar"
placeholder="Search for documents"
autosuggest={false}
customQuery={this.customQuery}
value={this.state.value}
onChange={this.onChange}
onKeyPress={this.handleKey}
/>
<ReactiveList
className="result-list"
componentId="SearchResult"
react={{
and: "documentSearch",
}}
dataField="label"
sortOptions={[
{ label: "Relevance", dataField: "_score", sortBy: "desc" },
]}
>
{({ data }) =>
data.map((item) => (
<div key={item.id} className="vertical-margin">
<DocumentResult
corpus={this.state.corpus}
document={item}
></DocumentResult>
</div>
))
}
</ReactiveList>
</ReactiveBase>
</div>
);
}

How to use properties on onClick from on child and parent component?

I'm now leaning react and having a lot of fun with, but also having my first issue than I cannot solved by myself.
I would like to use a child component to filter on his parent list. I mean I would like to use a child component to filter a list from his parent.. I hope my code would be more understandable than my explications...
Does anyone can explain how should I use onclick in both class and maybe optimize my code ? Thanks
product.jsx
class Items extends Component {
state = {
count: 0,
carbondioxide: [
{ key: 90, name: "All", value: "All" },
{ key: 91, name: "Still Water", value: "Still Water" },
{ key: 92, name: "Sparkling Water", value: "Sparkling Water" },
],
brands: [
{
key: 0,
name: "Fountain",
category: "Still Water",
},
{
key: 1,
name: "Kitchen",
category: "Sparkling Water",
},
{
key: 2,
name: "Shower",
category: "Still Water",
},
],
filterBrands: [],
};
componentDidMount() {
this.setState({
filterBrands: this.state.brands,
});
}
handleClick = (name) => {
let filterBrands = [];
if (name === "All") {
filterBrands = this.state.brands;
} else {
filterBrands = this.state.brands.filter(
(brands) => brands.category === name
);
}
this.setState({ filterBrands });
};
}
render() {
return (
<div className="ctg-flex">
<GroupButtonFilter
carbondioxide={this.state.carbondioxide}
onClick={this.handleClick.bind(this, name)} //filterBrands onclick
//onClick={() => {
// this.handleClick.bind(this, this.state.carbondioxide.name);
//}}
/>
{this.state.filterBrands.map((id, brands) => (
<Item
key={id.key}
dataImg={id.imageUrl}
dataText={id.name}
dataPrice={id.price}
/>
))}
</div>
);
}
}
export default Items;
and GroupeButtonFilter.jsx
class GroupButtonFilter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="group-button">
{this.props.carbondioxide.map(({ name, value }) => (
<Button
key={this.props.carbondioxide.key}
value={this.props.carbondioxide.value}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={this.props.onClicktest} //filterBrands onclick
>
{name}
</Button>
))}
</div>
);
}
}
There are couple of issue on your code.
You are binding your:
onClick={() => {
this.handleClick.bind(this, this.state.carbondioxide.name);
}}
and your handleClick is using arrow function so you can remove bind from this i.e
onClick={() => {
this.handleClick( this.state.carbondioxide.name);
}}
Still its not correct. which is our second point
In GroupButtonFilter you are expecting onClicktest and while passing in GroupButtonFilter you are sending onClick this can reduce to this:
<Button
key={this.props.carbondioxide.key}
value={this.props.carbondioxide.value}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={this.props.onClicktest} //filterBrands onclick
>
{name}
</Button>
You need to pass the value that button is clicked but in onClick you are sending carbondiooxide name. You need to do this. Inside GroupFilter:
<button
key={this.props.carbondioxide.key}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={() => this.props.onClicktest(name)} //filterBrands onclick
>
{name}
</button>
Here is complete code:
import React, { Component } from "react";
import "./styles.css";
class GroupButtonFilter extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="group-button">
{this.props.carbondioxide.map(({ name, value }) => (
<button
key={this.props.carbondioxide.key}
// onClick={this.props.handleClick.bind(this, this.name)} //filterBrands onclick
onClick={() => this.props.onClicktest(name)} //filterBrands onclick
>
{name}
</button>
))}
</div>
);
}
}
class Items extends Component {
state = {
count: 0,
carbondioxide: [
{ key: 90, name: "All", value: "All" },
{ key: 91, name: "Still Water", value: "Still Water" },
{ key: 92, name: "Sparkling Water", value: "Sparkling Water" }
],
brands: [
{
key: 0,
name: "Fountain",
category: "Still Water"
},
{
key: 1,
name: "Kitchen",
category: "Sparkling Water"
},
{
key: 2,
name: "Shower",
category: "Still Water"
}
],
filterBrands: []
};
componentDidMount() {
this.setState({
filterBrands: this.state.brands
});
}
handleClick = (name) => {
console.log(name);
let filterBrands = [];
if (name === "All") {
filterBrands = this.state.brands;
} else {
filterBrands = this.state.brands.filter(
(brands) => brands.category === name
);
}
this.setState({ filterBrands });
};
render() {
return (
<div className="ctg-flex">
<GroupButtonFilter
carbondioxide={this.state.carbondioxide}
onClicktest={this.handleClick}
// onClicktest={this.handleClick.bind(
// this.state.carbondioxide.name,
// this.name
// )}
/>
{this.state.filterBrands.map((id, brands) => (
<div key={id.name}>{id.name}</div>
))}
</div>
);
}
}
export default function App() {
return (
<div className="App">
<Items />
</div>
);
}
here is the demo:https://codesandbox.io/s/affectionate-fire-zcqc1?file=/src/App.js:0-2168
write a function in your parent component
handleClick = () => {
/// do your filtering
}
pass this handleClick to your child component
<GroupButtonFilter handleClickInParent ={this.handleClick} />
....
</GroupButtonFilter>
then inside your child component
<Button. onClick={() => this.props.handleClick())}>
</Button>

How to collect Switch value in React JS + Ant Design

I'm sorry for my basic knowledge and my basic english :)
My Question is: How to concenate switch value [I use Switch for each record in table]
This is the table
https://ibb.co/3TVLBK6
I've created table with one cell/field using Switch (On/Off)
And i want get the switch value when they are on
And here is the code
const columnsTableDepartmentModal = [
{
title: 'No',
dataIndex: 'no',
key: 'no',
},
{
title: 'Department',
dataIndex: 'department',
key: 'department',
},
{
title: 'Select',
dataIndex: 'select_department',
key: 'select_department',
render: (e, record) => (
<Switch
defaultChecked={e}
onChange={
(value) => onChangeSwitch(value,record)
}
checkedChildren="Yes"
unCheckedChildren="No"
/>
),
}];
This is what i now try
function onChangeSwitch(isSelect,record){
console.log(e); // True / False
console.log(record); // True / False
if(isSelect){
// push data to array
}
if(!isSelect){
// pop data from array
}
}
This is how i show the table
<Modal
title={modalDepartmentTitle}
visible={visibleDepartment}
width={800}
onOk={handleOkDepartment}
onCancel={handleCancelDepartment}
footer={[
<Button key="submit" type="primary" onClick={handleOkDepartment}>OK</Button>,
<Button key="button" type="danger" onClick={handleDeleteDepartment}>DELETE</Button>,
<Button key="back" onClick={handleCancelDepartment}>CANCEL</Button>,
]}
>
<Table
columns={columnsTableDepartmentModal}
dataSource={stateDepartment.data}
pagination={false}
scroll={{y: 325}}
/>
</Modal>
Expected result: 1,3,4
import React, { Component } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
import Switch from 'react-switch';
class App extends Component {
constructor() {
super();
this.state = {
checkedPos: [],
info: [],
};
}
componentWillMount()
{
let tmp = []
let pos = []
for (var i = 1; i < 6; i++) {
tmp.push("Info " + i)
pos.push(false);
}
this.setState({
info: tmp,
checkedPos: pos
})
}
handleChange(index, info)
{
if (!this.state.checkedPos[index])
{
this.setState(prev => ({
checkedPos: prev.checkedPos.map((val, i) => !val && i === index ? true : val),
}))
}
else if (this.state.checkedPos[index])
{
this.setState( prev => ({
checkedPos: prev.checkedPos.map((val, i) => val && i === index ? false : val),
}))
}
}
render() {
const listItems = this.state.info.map((item, index) =>
<div>
{item}
<Switch checked={this.state.checkedPos[index]}
onChange={ () => this.handleChange(index, this.state.info[index])}/>
{" Value is " + this.state.checkedPos[index]}
</div>
);
return (
<div>
{listItems}
</div>
);
}
}
render(<App />, document.getElementById('root'));
Demo here
Acording to #jose answer i've implemented to hook concept with this code
const [theArray, setTheArray] = useState([]);
const addEntry = useCallback((value) => {
setTheArray([...theArray, `${value}`]);
});
Then in function we can add value
function onChangeSwitch(isSelect,record){
console.log(isSelect); // True / False
console.log(record);
addEntry(record.no);
if(isSelect){
// push data to array
}
if(!isSelect){
// pop data from array
}
}
So when we display {enty}
<div key="adkfkdfkda">{theArray.map(entry =>
<span key={entry}>{entry},</span>
)}
</div>
We got value merged in string format
https://ibb.co/nQFK1C4
Thanks.

How can I update certain object in state with new data

I am making a notes taking application with React, when I click on a note in sidebar it opens in content area, then while changing text it updates the notes state, updates the current opened note with the current content inside the input area.
Can I do it with spread operator?
here is the full code on codesandbox
class App extends React.Component {
constructor() {
super();
this.state = {
notesList: [
{key: 0, title: "title of first note", note: "this is the first note"},
{key: 1, title: "title of second note", note: "this is another note"}
],
inputValue: null,
currentKey: null
};
}
noteTitleClicked = value => {
this.setState({
inputValue: value.note,
currentKey: value.key
});
};
updateNoteDetails = e => {
this.setState({
inputValue: e.target.value
});
};
render() {
const notes = this.state.notesList.map(note => (
<li key={note.key} onClick={e => this.noteTitleClicked(note)}>
{note.title}
</li>
));
const inputValue = this.state.inputValue;
return (
<div className="App">
<header>Header</header>
<div className="main">
<article>
{inputValue == null ? (
""
) : (
<input
className="noteDetails"
value={this.state.inputValue}
onChange={this.updateNoteDetails}
/>
)}
</article>
<nav>
<ul>{notes}</ul>
</nav>
</div>
<footer>Footer</footer>
</div>
);
}
}
Try this:
updateNoteDetails = e => {
const updated = this.state.notesList.map(n => {
if (n.key === this.state.currentKey)
return { ...n, note: e.target.value };
return n;
});
this.setState({
inputValue: e.target.value,
notesList: updated
});
};
This this is the demo: https://codesandbox.io/s/k591vor8v3

How to update state in map function in reactjs

I am having 4 buttons each button have name id and selected boolean flag.
What I am trying to achieve is, on click of button, boolean button flag should be changed of that particular button. For this, I need to setState in map function for that particular button Id.
My issue is I am unable to setState in map function for that particular clicked button, its btnSelected should be changed
My aim is to create a multi-select deselect button.Its kind of interest selection for the user and based on that reflect the UI as well my array. Here is my code.
Thanks in anticipation.
import React, { Component } from "react";
import { Redirect } from "react-router-dom";
export default class Test extends Component {
constructor(props, context) {
super(props, context);
this.handleChange = this.handleChange.bind(this);
this.state = {
value: "",
numbers: [1, 2, 3, 4, 5],
posts: [
{
id: 1,
topic: "Animal",
btnSelected: false
},
{
id: 2,
topic: "Food",
btnSelected: false
},
{
id: 3,
topic: "Planet",
btnSelected: false
},
{ id: 4, topic: "Nature", btnSelected: false }
],
allInterest: []
};
}
handleChange(e) {
//console.log(e.target.value);
const name = e.target.name;
const value = e.target.value;
this.setState({ [name]: value });
}
getInterest(id) {
this.state.posts.map(post => {
if (id === post.id) {
//How to setState of post only btnSelected should change
}
});
console.log(this.state.allInterest);
if (this.state.allInterest.length > 0) {
console.log("Yes we exits");
} else {
console.log(id);
this.setState(
{
allInterest: this.state.allInterest.concat(id)
},
function() {
console.log(this.state);
}
);
}
}
render() {
return (
<div>
{this.state.posts.map((posts, index) => (
<li
key={"tab" + index}
class="btn btn-default"
onClick={() => this.getInterest(posts.id)}
>
{posts.topic}
<Glyphicon
glyph={posts.btnSelected === true ? "ok-sign" : "remove-circle"}
/>
</li>
))}
</div>
);
}
}
Here's how you do something like this:
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (e) => {
const { posts } = this.state;
const { id } = e.target;
posts[id].selected = !this.state.posts[id].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="radio" id={i} key={i} checked={p.selected} onClick={this.handleClick} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here.
You can do this by passing the index from the map into each button's handleClick function, which would then return another function that can be triggered by an onClick event.
In contrast to Colin Ricardo's answer, this approach avoids adding an id prop onto each child of the map function that is only used for determining the index in the handleClick. I've modified Colin's example here to show the comparison. Notice the event parameter is no longer necessary.
class App extends Component {
state = {
posts: [{
name: 'cat',
selected: false,
}, {
name: 'dog',
selected: false
}]
}
handleClick = (index) => () => {
const { posts } = this.state;
posts[index].selected = !this.state.posts[index].selected
this.setState({ posts })
}
render() {
return (
<div>
<form>
{this.state.posts.map((p, i) => {
return (
<div>
<label>{p.name}</label>
<input type="checkbox" key={i} checked={p.selected} onClick={this.handleClick(i)} />
</div>
)
})}
</form>
</div>
);
}
}
render(<App />, document.getElementById('root'));
Working example here

Resources