How to do setState for an object inside constructor -> state? - reactjs

How to do setState for {items.name} an object which is inside constructor -> this.state -> items: { name: '', age:'' }

Inside the constructor instead on doing setState you can assign value to this.state
this.state = {
name: "",
age: ""
}
But there is rarely a use case where in you need to do it this way.

If you need to set the state of bugDetail ,
in constructor you can do this:
constructor(props) {
super(props);
this.state = { bugTitle : '',
bugDescription : '',
bugType : '',
bugDetail : { title : '', description : '', type: '' },
bugDetailArray : [] } }
do the following later: ->
this.setState({bugDetail:{title:"updated",description : 'olderdesc', type:"older"}})
also can do:->
updateTitle(updatedTitle){
let newBugdetail = this.state.bugDetail;
newBugdetail.title = updatedTitle;
this.setState({bugDetail:newBugdetail })
}
else you need to keep the title as an outside key in the state

I believe that your constructor looks like this
constructor(props) {
super(props);
this.state = {
bugTitle : '',
bugDescription : '',
bugType : '',
bugDetail : {
title : '',
description : '',
type: ''
},
bugDetailArray : []
}
}
So in order to change the state using setState in your function
someFunction = (e) => {
let inputName = e.target.name;
let inputValue = e.target.value;
let updatedFormState = Object.assign({}, this.state);
updatedFormState.bugDetail["title"] = inputValue;
this.setState(updatedFormState);
}

Related

Cannot read property 'files' of undefined for sending multiple images

Code
class Add_Give_Item_Form extends Component {
constructor(props) {
super(props);
this.state = {
// #インプット情報用
info: {
name: '',
owner: '',
keyword1: '',
keyword2: '',
keyword3: '',
bland: '',
state: '未使用、新品',
category: '',
images: [],
detail: '',
},
// Validation用
//  urlは必須項目ではないのでValidationには含めない
message: {
name: '',
keyword1: '',
keyword2: '',
keyword3: '',
state: '',
category: '',
detail: '',
},
allCategory: null,
allBland: null,
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleImageSelect = this.handleImageSelect(this);
}
////
...
////
handleChange = (e) => {
const name = e.target.name;
const value = e.target.value;
const { info, message } = this.state;
this.setState({
info: { ...info, [name]: value },
});
this.setState({
message: { ...message, [name]: this.validator(name, value) },
});
};
handleImageSelect = (e) => {
this.setState({
info: { ...this.state.info, images: [...this.state.info.images, e.target.files] },
});
};
render() {
const { info, message, allCategory, allBland } = this.state;
// setStateが完了するまではnullにする。
if (this.state.allCategory === null || this.state.allBland === null) {
return <CircularProgress />;
} else {
return (
<div>
///////
.....
///////
<label>Images</label>
<input type="file" multiple onChange={this.handleImageSelect} />
What I want to do
I would like to catch each file sent by a user and put into state as this.state.info.images which is an array.
I saw some questions on stackoverflow and then I found some solutions. When I wrote the same code as what I saw, I got an error like below.
cannot read property files of undefined
I should write the same code but I got the error for some reasons.
I may take another way to realize what I want to do, but I want to write readable codes and figure out why it is happening.
I would like you to teach me why this happens and solutions.
Thank you very much.
I just notice I didn't put bind with this.handleImageSelect = this.handleImageSelect(this).
Now it works well.
Thank you very much.

replace array object at perticular index in setState

I have an update button which gets me the updated object and I have the index at which I want to replace the array with this object:
updateVal = () => {
console.log("this.state::", this.state);
let alleditvals = {
username: this.state.uname_edit,
password: this.state.pass_edit,
address: this.state.address_edit
};
console.log("w::", this.state.add_data[this.state.count_edit]);
console.log("alleditvals::", alleditvals);
console.log("this.state.add_data[1]", this.state.add_data[1]);
this.state.add_data.map((a, i) => {
console.log("i::", i);
console.log("a::", a);
if (this.state.count_edit == i) {
console.log(this.state.add_data[i]);
}
});
}
the state is like this:
this.state = {
uname: "",
pass: "",
address: "",
salary: "",
add_data: [],
edit_obj: {},
edit_showui: false,
uname_edit: "",
pass_edit: "",
address_edit: "",
count_edit: null,
changed_after_edit: {},
errorfields: {
uname_err: "",
pass_err: "",
address_err: "",
salary_err: "",
valid_user: false,
valid_pass: false,
valid_address: false,
valid_salary: false
}
};
so my array is add_data which i want to replace with alleditvals at index this.state.count_edit. I have also checked on map function that if the index of current count matched the add_data index, please replace it, but don't know how to replace it.
if(this.state.count_edit == i){
console.log(this.state.add_data[i])
}
You can update your component state with the setState method, and use the array method map on your add_data array and replace the element at index count_edit with the alleditvals object.
updateVal = () => {
let alleditvals = {
username: this.state.uname_edit,
password: this.state.pass_edit,
address: this.state.address_edit
};
this.setState(({ count_edit, add_data }) => ({
add_data: add_data.map((item, index) =>
index === count_edit ? alleditvals : item
)
}));
}
Thanks to setState, you can update state easily.
class App extends Component {
constructor(props){
super(props)
this.state = {
allData: [],
index: 0
}
}
componentWillMount()
{
this.state.allData.push({ name1: "Test1", name2: "Test2"});
}
push1 = () =>
{
this.setState({
index: 1
})
}
push2 = () =>
{
this.setState({
index: 2
})
}
render() {
const list = this.state.allData.map((value, index) => {
return (
<div>
{ this.state.index === 1? value.name1 : value.name2 }
</div>
)
})
return (
<div>
<button onClick={this.push1}>Push 1</button><br/><br/>
<button onClick={this.push2}>Push 2</button><br/><br/>
<div>
{list}
</div>
</div>
);
}
}
In this example I pressed Push2 = Test2 shows. If you press Push1, Test1 will appear.

How to set initial state dynamically?

My initial state varies depending on how many items I get from the API call.
So basically sometimes it looks like this:
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: '',
}
...
and some times it might look like this depending on the data returned by the database.
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: '',
activeItem4: '',
activeItem5: '',
}
...
Is there a way to set the initial state keys dynamically?
here's what I have so far:
class MyComponent extends Component {
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
}
// Set the value for each product on the store
handleItemClick = (e, { name, children }) => this.setState({[e.target.name]: children })
let buttonGroup = _.times(products.length, i => (
<Button.Group>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val1'}
onClick={this.handleItemClick}
>
Val1
</Button>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val2'}
onClick={this.handleItemClick}>
Val2
</Button>
<Button
name={`activeItem${i}`}
active={this.state[`activeItem${i}`] === 'Val3'}
onClick={this.handleItemClick}>
Val3
</Button>
</Button.Group>
)
render() {
return(
<div>
<Grid container>{selectSizeInSideBar}</Grid>
</div>
)
}
}
So the issue is that if products.length returned by the DatabBase is 4
I should have in my initial state like this
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
}
but if my products.length returned by the DatabBase is 6 then
my initial state should look like this:
state = {
activeItem0: '',
activeItem1: '',
activeItem2: '',
activeItem3: ''
activeItem4: ''
activeItem5: ''
}
You can make a method that initialize your state after your component is ready ( let's say the data of your API has been received ), so its preferrable to make this in the componentDidMount.
const initializeStateForKeys = ( products ) => {
const fakeState = {};
_.each( products, product => {
fakeState[ product.id ] = { id: product.id ,isActive: product.isActive }
} );
return fakeState
}
and you should use it like this:
componentDidMount(){
API.fetchMyProducts()
.then( response => {
this.setState( { products: response.data.products }
, () => {
this.initializeStateForKeys( this.state.products);
});
});
}

NextJS: Use same component in multiple routes for multiple pages

In my NextJS app, I have a search bar component OrderSearchBar.js and I want to use it in both index.js and /purchases.js pages but with different endpoints.For example,if I click search button on the index.js page,it should post form content to /orders and on the /purchases.js, form content should post to /purchaseDetails.Is there any way to accomplish this?
OrderSearchBar.js
class OrderSearchBar extends Component{
constructor(props) {
super(props);
this.onChangeInput = this.onChangeInput.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
}
}
onChangeInput(e) {
this.setState({
[e.target.name]: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
const t = {
nature: this.state.nature,
type: this.state.type,
searchBy: this.state.searchBy,
startDate: this.state.startDate,
endDate: this.state.endDate,
keyword: this.state.keyword
}
axios.post('/search', t)..then(res => console.log(res.data));
/*I can do this for single endpoint.but how do I add multiple endpoints
for use in different pages?*/
this.setState({
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
});
}
You can differentiate the current location in your orderSearchBar.js
by getting the pathname of window.location object.
onSubmit(e) {
e.preventDefault();
const t = {
nature: this.state.nature,
type: this.state.type,
searchBy: this.state.searchBy,
startDate: this.state.startDate,
endDate: this.state.endDate,
keyword: this.state.keyword
}
const pathName = window && window.location.pathname;
const destination = (pathName === '/purchases') ? '/purchaseDetails' : '/orders'
axios.post(destination, t)..then(res => console.log(res.data));
this.setState({
nature: '',
type: '',
searchBy: '',
startDate: '',
endDate: '',
keyword: ''
});
}
While you could use window property, this might not work if you're using Nuxt.js or other server side rendering, since the window object is not present.
Instead, I suggest you pass a prop down to your component, say:
<component :type="'isPurchaseDetails'">
or for purchases
<component :type="'isPurchases'">

React - state won't update

i am building small react app and i have strange situation that state won't update. Here is example:
class App extends Component {
constructor() {
super();
this.state = {
locale: 'de',
countryList: [],
fetchInProgress: true,
serverError: {},
person: {
salutation: '',
firstName: '',
lastName: '',
birthDate: '',
nationality: '',
address: '',
zipCode: '',
city: '',
country: '',
mobileNumber: '',
email: '',
correspondanceLanguage: '',
}
};
}
componentDidMount() {
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
}
}
I tried also using other approaches:
componentDidMount() {
const temp = {...this.state};
temp.fetchInProgress = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
componentDidMount() {
const temp = {...this.state};
temp['fetchInProgress'] = false;
this.setState(temp),()=>console.log('State updated', this.state)
}
But never gets state updated. Any help?
You have syntax errors in all of your approaches. Note that setState() has the following format:
setState(updater, callback)
where updater can either be a function or an object and where callback is a function.
Starting with your initial approach:
this.setState({
fetchInProgress: false
}),()=>console.log('State updated', this.state)
should instead be:
this.setState({
fetchInProgress: false
},()=>console.log('State updated', this.state))
The other code is correct until, again, you get to the setState() part:
this.setState(temp),()=>console.log('State updated', this.state)
should instead be:
this.setState(temp,()=>console.log('State updated', this.state))

Resources