Pass state to page on form submit? - reactjs

I have a state on one page, and when i submit a form I'd like to redirect to another page with the state of the source page, and populate the state on the new page with the old state on the old page haha if that makes sense. Hopefully my code attempt can explain it better.
class NewFormDetails extends Component {
constructor(props) {
super(props);
this.state = {
language: this.props.language,
siteName: '',
counties: '',
siteAddress: '',
siteEmail: '',
siteNumber: '',
siteCat: '',
openTimes: '',
fees: '',
access: '',
gps: '',
w3w: '',
txtHeader: '',
txtContent: '',
isLoading: false
};
}
validateForm() {
if (this.state.siteName != '' &&
this.state.siteAddress != '' &&
this.state.siteEmail != '' &&
this.state.siteNumber != '' &&
this.state.openTimes != '' &&
this.state.fees != '' &&
this.state.access != '' &&
this.state.gps != '' &&
this.state.w3w != '' &&
this.state.txtHeader != '' &&
this.state.txtContent != '') {
return true;
} else {
return false;
}
}
handleChange = e => {
this.setState({ ...this.state, [e.target.name]: e.target.value });
console.log(this.state);
}
handleSubmit = event => {
event.preventDefault();
/* try {
await this.createSiteDetails({
siteName: this.state.siteName,
siteAddress: this.state.siteAddress,
siteCounty: this.state.counties,
siteNumber: this.state.siteNumber,
siteEmail: this.state.siteEmail,
siteCategory: this.state.siteCat,
siteOpeningTimes: this.state.openTimes,
siteFees: this.state.fees,
siteAccess: this.state.access,
siteGPS: this.state.gps,
siteW3W: this.state.w3w,
siteHeaderText: this.state.txtHeader,
siteContentText: this.state.txtContent
});
this.props.history.push("/");
} catch (e) {
alert(e);
this.setState({ isLoading: false });
} */
console.log(this.state);
this.props.history.push({
pathname:"/newSite/tours",
state:{
value: this.state
}
});
}
And here is the page i redirect to and attempt to get the state from the other page
class NewFormTours extends Component {
constructor(props) {
super(props);
this.state = {
language: this.props.language,
tourName: '',
waypoints: '',
duration: '',
toursTxtHeader: '',
toursTxtContent: '',
siteName: this.siteName,
counties: this.props.counties,
siteAddress: this.props.siteAddress,
siteEmail: this.props.siteEmail,
siteNumber: this.props.siteNumber,
siteCat: this.props.siteCat,
openTimes: this.props.openTimes,
fees: this.props.fees,
access: this.props.access,
gps: this.props.gps,
w3w: this.props.w3w,
detailsTxtHeader: this.props.detailsTxtHeader,
detailsTxtContent: this.props.detailsTxtContent,
};

You can use react router to pass data to new component.
Below discussion should be helpful.
How do i pass state through React_router?

Related

ReactJS Add new row to Table

I create Table dynamicaly:
In component Table I set the default values of table in json:
constructor(props) {
super(props);
this.state = {
data: [
{'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''}
]
};
}
Then use it to render table:
render() {
return (
<div className={styles}>
<table>
<thead>
<tr>{this.getHeader()}</tr>
</thead>
<tbody>
{this.getRowsData()}
</tbody>
<button onClick={this.addRow}>
Add new row
</button>
</table>
</div>
);
}
This is a methods realization:
getKeys = function () {
return Object.keys(this.state.data[0]);
};
getHeader = function () {
var keys = this.getKeys();
return keys.map((key, index) => {
return <th key={key}>{key.toLowerCase()}</th>
})
};
getRowsData = function () {
var items = this.state.data;
var keys = this.getKeys();
return items.map((row, index) => {
return <tr key={index}><RenderRow key={index} data={row} keys={keys}/></tr>
})
};
And now I try to add new row, using this method:
addRow = function () {
let newRows = this.state.data.push({'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''});
this.setState({data: newRows});
};
But when I try it, I receive the following error: TypeError: Cannot convert undefined or null to object
in
return Object.keys(this.state.data[0]);
Indeed, after I push a new object to "data", I see, that "data" not containts any elements. Although before that it contained 1 element: {'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''}
This is the wrong in your function. Push will return you the values that pushed into the array,
addRow = () => {
let existingRows = this.state.data;
existingRows.push({'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''});
this.setState({ data: existingRows });
};
If You wish to use arrow function for addRow the below will not be needed! Or if you wish to use the normal function you are using you have to change the button onClick as below,
addRow = function () {
let existingRows = this.state.data;
existingRows.push({ 'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': '' });
this.setState({ data: existingRows });
};
<button onClick={() => this.addRow()}>
Add new row
</button>
The value of newRows will be {'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': ''} which you are setting as state instead it should be an array.
So what you can do is:-
let rowsData = this.state.data;
existingRows.push({ 'Date': '', 'Operation': '', 'Amount': '', 'Item_of_expenditure': '', 'Balance': '' });
this.setState({ data: rowsData });

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.

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