I have this.state with an array, and in array I want to change title, but it is not working. Help me please
Code:
this.state =
{
list: [{title: "1"}, {title: "2"}],
}
// changing title
this.setState({
this.state.list.title: "newTitle"
}],
try this
this.setState({
list: [{title: 'new title'}, { title: 'other title' }]
});
Example
class App extends React.Component {
state = { list: [{title: "1"}, {title: "2"}] };
updateTitle = (index) => {
var { list } = this.state;
list[index].title = `Updated title ${index}`;
this.setState({list});
}
updateTitles = () => {
var { list } = this.state;
list.forEach((item, k) => {
item.title = `Title ${k}`;
});
this.setState({list});
}
render(){
var { list } = this.state;
return (
<div>
<button onClick={this.updateTitles}>Update Title</button>
<ul>
{list.map((item, k) => (
<li onClick={() => this.updateTitle(k)} key={item.title}>{item.title}</li>
))}
</ul>
</div>
);
}
}
I can't get your question correctly. If you want to change value of title key of every child of list array just declare a function like this
function changeValue () {
let newList = this.state.list
newList.forEach(item => {
item.title = 'newTitle'
})
this.setState = ({
list: newList
})
}
Related
i want to replace the values of the nested array object like the below one, when button is clicked it will replace the old values of the x indexed object and set the new values there.
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData:[
{
id:1,
title:"OldTitle1"
},
{
id:2,
title:"OldTitle2"
}
],
}
this.changeTab = this.changeTab.bind(this)
}
changeTab(){
const newData={
id=3,
title="New One"
}
//replace the above new data in the second object of nested array in state
}
render(){
return(
<button type="button" >Add</button>
)
;}
}
export default compo
the state should be like this after
tabsData:[
{
id:1,
title:"OldTitle"
},
{
id:3,
title:"New One"
}
]
Not able to comment as my rep is less than 50...based on an idea of what you need here is the code.
https://codesandbox.io/s/brave-lumiere-dh9ry?file=/src/App.js
const [data, setData] = React.useState([
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]);
const newData = { id: 3, title: "New One" };
const addData = () => {
const newArr = data;
newArr[1] = newData;
console.log("newArr>>>>", newArr);
setData([...newArr]);
};
You could do something like this...
import React from "react";
class compo extends React.Component {
constructor() {
super();
this.state = {
tabsData: [
{
id: 1,
title: "OldTitle1"
},
{
id: 2,
title: "OldTitle2"
}
]
};
this.changeTab = this.changeTab.bind(this);
}
changeTab() {
const newData = {
id: 3,
title: "New One"
};
// Make duplicate since you can't mutatue state
let newTabData = [...this.state.tabsData];
const id = 2; // id to be removed
// CASE 1: If you want to maintain order
const index = newTabData.findIndex((data) => data.id === id);
if (index > -1) {
// replace oldData with newData
newTabData.splice(index, 1, newData);
} else {
// simply add newData at last
newTabData.push(newData);
}
// CASE 2: If order doesn't matter
// // remove oldData
// newTabData = newTabData.filter((data) => data.id !== id);
// // add new data at last
// newTabData.push(newData);
// finally update the state irrespective of any case
this.setState({ tabsData: newTabData });
}
render() {
return (
<div>
<button type="button">
Add
</button>
<button type="button" onClick={this.changeTab}>
Change
</button>
<br />
{JSON.stringify(this.state, null, 2)}
</div>
);
}
}
export default compo;
I need to control a list of list of input like this:
import React from "react";
import "./styles.css";
const testData = [
{
name: "list 1",
content: [
{
id: 1,
value: " this is value 1 of list 1"
},
{
id: 2,
value: " this is value 2 of list 1"
},
{
id: 3,
value: " this is value 3 of list 1 "
}
]
},
{
name: "list 2",
content: [
{
id: 1,
value: " this is value 1 of list 2"
},
{
id: 2,
value: " this is value 2 of list 2"
},
{
id: 3,
value: " this is vainput'liste 3 of list 2"
}
]
}
];
class MyList extends React.Component {
constructor(props) {
super(props);
this.state = {
data: this.props.list
};
}
handleChange = (e, index) => {
const newData = this.state.data;
newData[index] = e.target.value;
this.setState({
data: newData
});
};
updateData = newData => {
this.setState({
data: newData
});
};
add = () => {
const newData = this.state.data;
newData.push({
id: newData.length + 1,
value: "new data"
});
this.setState({
data: newData
});
};
remove = (e, index) => {
const newData = this.state.data;
newData.splice(index, 1);
this.setState({
data: newData
});
};
save = (e, index) => {
//TODO
};
render() {
return (
<div className="App">
<button onClick={this.add}> Add </button>
<button onClick={this.save}> save </button>
<tr>input'list
{this.state.data.map((item, index) => (
<td>
<input
value={item.value}
onChange={e => this.handleChange(e, index)}
/>
title
<button onClick={e => this.remove(e, index)}> remove </button>
</td>
))}
</tr>
</div>
);
}
}input'list
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
title: testData[0].name,
data: testData[0].content
};
this.ref = React.createRef();
}
changeList = (e, index) => {
this.setState({
title: testData[index].name,
data: testData[index].content
});
this.ref.current.updateData(testData[index].content);
};
render() {
return (
<>
{testData.map((item, index) => (
<button onClick={e => this.changeList(e, index)}>
{" "}
{item.name}{" "}
</button>
))}
this is {this.state.title}
<MyList ref={this.ref} list={this.state.data}>
{" "}
</MyList>{" "}
</>
);
}
}
export default App;
I need some basic method like show list, save, add more input in list, remove ... And with my code, everything works fine. But I feel it's not clean since there's many ways to do 1 thing in React. Can someone read it and give me some feedback? There's 2 things I thought are not good, but I don't know how to improve:
function handleChange of component MyList: I have to calculator index of input to re-render.
I use A Ref to update and get Data from component MyList.
I am trying to add draggable attributes to a component that is rendered out, however, I don't know where to add them in exactly. So they at least render out but the array does no update on OnDragEnd when the item is dropped. The component:
const Item = props => {
const finishedButton = <button onClick={props.handleComplete} className="finishedButton">✔</button>
return (
<li className="background"
draggable
onDragStart={props.dragStart}
onDragEnd={props.dragEnd}
>
{finishedButton}{props.item}
</li>
and in the render in App
<ul onDragOver={e => this.dragOver(e)}>
{this.state.items.map((item, i)=> (
<Item
data-id={i}
key={i}
dragStart={e => this.dragStart(e)}
dragEnd={e => this.dragEnd(e)}
item={item.text}
/>
))}
</ul>
Codepen: https://codepen.io/Matt-dc/pen/zbYKNv
In your dragEnd function this.draggedElem is not defined. And therefore prevIndex & newIndex is undefined as well, which leads to data.splice returning the old state.
I am not sure about your logic, but seems it works
let placeholder = document.createElement("li");
placeholder.className = "placeholder";
const Item = props => {
const finishedButton = <button onClick={props.handleComplete} className="finishedButton">✔</button>
return (
<li className="background"
draggable
onDragStart={props.dragStart}
onDragEnd={props.dragEnd}
onDragOver={props.dragOver}
>
{finishedButton}{props.item}
>
</li>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: [
{id: 1, text: "clean car", complete: false},
{id: 2, text: "wash dog", complete: false},
{id: 3, text: "water plants", complete: false},
{id: 4, text: "prune shrubs", complete: false},
{id: 5, text: "tidy house", complete: false}
],
input: ""
}
this.dragStart = this.dragStart.bind(this);
this.dragOver = this.dragOver.bind(this);
this.dragEnd = this.dragEnd.bind(this);
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange = e => {
this.setState({
input: e.target.value
});
}
handleSubmit = () => {
let newItem = {};
newItem.id = uuid.v4();
newItem.text = this.state.input;
newItem.complete = false;
let newItems = this.state.items.concat(newItem);
this.setState({
items: newItems,
});
this.setState({input: ''})
}
handleComplete = e => {
}
dragStart = e => {
this.draggedElem = e.target;
e.dataTransfer.setData('text/html', this.draggedElem);
}
dragOver = e => {
e.preventDefault();
//this.draggedElem.style.display = "none";
if(e.target.className === 'placeholder') return;
this.newIndex = e.target
}
dragOverItem = (id,e) => {
this.to = id;
}
dragEnd = (from,e) => {
let data = this.state.items;
let prevIndex = from;
let newIndex = this.to;
console.log(`from ${prevIndex} to ${newIndex}`)
//if(prevIndex < newIndex) newIndex --;
data.splice(newIndex, 0, data.splice(prevIndex, 1)[0]);
this.setState({ items: data });
}
render() {
return(
<div>
<input onChange={this.handleChange} value={this.state.input} />
<button onClick={this.handleSubmit}>Add item</button>
<ul onDragOver={this.dragOver}>
{this.state.items.map((item, i)=> (
<Item
data-id={i}
key={i}
dragOver={this.dragOverItem.bind(this,i)}
dragStart={e => this.dragStart(e)}
dragEnd={this.dragEnd.bind(this, i)}
item={item.text}
/>
))}
</ul>
<p>{this.state.input}</p>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
I have an issue with my reactjs code where the render() function won't print an array in the order that it is stored in my state object.
Here's my code which is pretty simple:
import React from "react";
export default class DonationDetail extends React.Component {
constructor(props) {
super(props);
this.state = { content: [] };
}
componentDidMount() {
let state = this.state;
state.content.push({ food: "burger" });
state.content.push({ food: "pizza" });
state.content.push({ food: "tacos" });
this.setState(state);
}
addPaymentItem() {
const item = { food: "" };
let state = this.state;
state.content.unshift(item);
this.setState(state);
}
render() {
console.log(this.state);
let ui = (
<div>
<button type="button" onClick={() => this.addPaymentItem()}>
add to top
</button>
{this.state.content.map((item, key) => (
<input type="text" key={key} defaultValue={item.food} />
))}
</div>
);
return ui;
}
}
When you press the button add to top, a new item is placed to the front of the state.content array, which you can verify from the console.log(this.state) statement. But what's unusual is that the HTML that is generated does NOT add this new item to the top of the user interface output. Instead, another input field with the word taco is placed at the bottom of the list in the user interface.
Why won't ReactJS print my state.content array in the order that it is actually stored?
You can use the array index as key when the order of the elements in the array will not change, but when you add an element to the beginning of the array the order is changed.
You could add a unique id to all your foods and use that as key instead.
Example
class DonationDetail extends React.Component {
state = { content: [] };
componentDidMount() {
const content = [];
content.push({ id: 1, food: "burger" });
content.push({ id: 2, food: "pizza" });
content.push({ id: 3, food: "tacos" });
this.setState({ content });
}
addPaymentItem = () => {
const item = { id: Math.random(), food: "" };
this.setState(prevState => ({ content: [item, ...prevState.content] }));
};
handleChange = (event, index) => {
const { value } = event.target;
this.setState(prevState => {
const content = [...prevState.content];
content[index] = { ...content[index], food: value };
return { content };
});
};
render() {
return (
<div>
<button type="button" onClick={this.addPaymentItem}>
add to top
</button>
{this.state.content.map((item, index) => (
<input
type="text"
key={item.id}
value={item.food}
onChange={event => this.handleChange(event, index)}
/>
))}
</div>
);
}
}
ReactDOM.render(<DonationDetail />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Instead of:
componentDidMount() {
let state = this.state;
state.content.push({ food: "burger" });
state.content.push({ food: "pizza" });
state.content.push({ food: "tacos" });
this.setState(state);
}
Try
componentDidMount() {
this.setState(prevState => ({
content: [
...prevState.content,
{ food: "burger" },
{ food: "pizza" },
{ food: "tacos" },
]
}));
}
and
addPaymentItem() {
const item = { food: "" };
let state = this.state;
state.content.unshift(item);
this.setState(state);
}
to
addPaymentItem() {
this.setState(prevState => ({
content: [
{ food: "" },
...prevState.content,
]
}));
}
My Project is, an array of objects where i get only the names and render on screen of form 3 in 3, with button next and previous change the names, and can to filter for letters.
I would want add a new value, typped on input and clicked in the button add.
My code button:
addItem = () => {
const inValue = {
id: 0,
name: this.state.input
}
this.setState({
filtered: this.state.filtered.concat(inValue),
currentPage: 0
})
}
I would want the value inserted in the filtered array.
My code all:
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
const peoples =[{id:0, name:"Jean"},
{id:1, name:"Jaha"},
{id:2, name:"Rido"},
{id:3, name:"Ja"},
{id:4, name:"Letia"},
{id:5, name:"Di"},
{id:6, name:"Dane"},
{id:7, name:"Tamy"},
{id:8, name:"Tass"},
{id:9, name:"Ts"},
{id:10, name:"Abu"},
{id:11, name:"Ab"}];
this.state = {
elementsPerPage:3,
currentPage:0,
peoples,
input: "",
filtered: peoples,
teste: '',
};
}
getValueInput = (evt) => {
const inputValue = evt.target.value;
this.setState({ input: inputValue });
this.filterNames(inputValue);
}
filterNames = (inputValue)=> {
const { peoples } = this.state;
this.setState({
filtered: peoples.filter(item =>
item.name.includes(inputValue)),
currentPage:0
});
const Oi = this.state.filtered.map(item=>item.name);
if(Oi.length<=0){
alert('Você está adicionando um nome')
}
console.log(Oi)
}
elementsOnScreen = () => {
const {elementsPerPage, currentPage, filtered} = this.state;
return filtered
.map((item) => <li key={item.id}> {item.name} <button onClick={() => this.remove(item.name)}> Delete </button> </li>)
.slice(currentPage*elementsPerPage, currentPage*elementsPerPage + elementsPerPage);
if(this.state.filtered.length < 1){
this.setState({currentPage: this.state.currentPage - 1})
}
}
remove = (id) => {
console.log(this.state.filtered.length)
if(this.state.filtered.length < 0){
this.setState({currentPange: this.state.currenPage - 1})
}
this.setState({filtered: this.state.filtered.filter(item => item.name !== id) })
}
nextPage = () => {
console.log(this.state.filtered)
const {elementsPerPage, currentPage, filtered} = this.state;
if ((currentPage+1) * elementsPerPage < filtered.length){
this.setState({ currentPage: this.state.currentPage + 1 });
}
}
previousPage = () => {
const { currentPage } = this.state;
if(currentPage - 1 >= 0){
this.setState({ currentPage: this.state.currentPage - 1 });
}
}
addItem = () =>{
const inValue = {id:0 ,name: this.state.input}
this.setState({filtered: this.state.filtered.concat(inValue), currentPage: 0})
}
render() {
return (
<div>
<button onClick={this.addItem}> Add </button>
<input type="text" onChange={ this.getValueInput }></input>
<button onClick={this.previousPage}> Previous </button>
<button onClick={this.nextPage}> Next </button>
<h3>Current Page: {this.state.currentPage}</h3>
<ul>Names: {this.elementsOnScreen()}</ul>
</div>
);
}
}
export default App;
You would have the array of objects contained within your state, then use setState
this.state = {
elementsPerPage:3,
currentPage:0,
peoples,
input: "",
filtered: peoples,
teste: '',
peoples: [
{id:0, name:"Jean"},
{id:1, name:"Jaha"},
{id:2, name:"Rido"},
{id:3, name:"Ja"},
{id:4, name:"Letia"},
{id:5, name:"Di"},
{id:6, name:"Dane"},
{id:7, name:"Tamy"},
{id:8, name:"Tass"},
{id:9, name:"Ts"},
{id:10, name:"Abu"},
{id:11, name:"Ab"}];
};
To update the peoples array, you would first need to create a copy of the peoples array, modify the copy, then use setState to update.
let { peoples } = this.state;
peoples.push({ id:12, name:"Jean"})
this.setState({peoples: peoples})
Looks like you are already updating your state with the typed input.
So in your add button you can get the state value and push it to your people array. Something like this:
addItem = () => {
const { inputValue, people } = this.state;
if (!inputValue) return; // check if inputValue has any value
people.push({ id: people.length+1, name: inputValue )} // I don't recommend using sequencial ids like this, you'd better have a handler to generate it for you
this.setState({ people, inputValue: '' }); // update people and clear input
}
Hope it helps