I have what I call a parent component. It is a modal. I am trying to update a variable from a child component, namely the ShippingBlock. I am trying to update shippingMethod
.
import React from 'react';
import "./Checkout.scss"
import AddressBlock from './AddressBlock';
import PaymentBlock from './PaymentBlock';
import ShippingBlock from './ShippingBlock';
import TotalsBlock from './TotalsBlock';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
class CheckoutModal extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'React'
};
}
render() {
let shippingMethod = null;
function setShippingMethod(method) {
shippingMethod = method;
}
const buttonStyles = {
position: "absolute",
top: "-35px",
right: "10px",
border: "0",
background: "none"
};
return (
<Modal id="checkout"
isOpen
size='xl'>
<button onClick={this.props.onRequestClose} style={buttonStyles}>x</button>
<ModalHeader className="header">
Checkout
</ModalHeader>
<ModalBody>
<div className="row">
<AddressBlock />
<ShippingBlock setShippingMethod={setShippingMethod} shippingMethod={shippingMethod}/>
</div>
<div className="row">
<PaymentBlock />
<TotalsBlock />
</div>
</ModalBody>
</Modal>
);
}
}
export default CheckoutModal;
import React from 'react';
import Config from 'config';
import "./Checkout.scss"
class ShippingBlock extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'React',
shippingMethods: [],
defaultMethod: this.props.shippingMethod
};
}
async componentDidMount() {
console.log('Running componentDidMount')
const tokenString = sessionStorage.getItem("token");
const token = JSON.parse(tokenString);
let headers = new Headers({
"Accept": "application/json",
"Content-Type": "application/json",
'Authorization': 'Bearer ' token.token
});
const response = await fetch(Config.apiUrl `/api/Shipping/GetShippingMethods`, {
method: "GET",
headers: headers
});
const json = await response.json();
console.log(json);
this.setState({ shippingMethods: json });
if (this.state.defaultMethod === null) {
const mresponse = await fetch(Config.apiUrl `/api/Users/GetDefaultShippingMethod`, {
method: "GET",
headers: headers
});
const mjson = await mresponse.json();
console.log(mjson);
this.setState({ defaultMethod: mjson });
}
}
setShippingMethod(e) {
console.log('Shipping method ' JSON.stringify(e.target.value));
this.props.setShippingMethod(e.target.value);
this.state.defaultMethod = e.target.value;
}
render() {
const shippingMethods = this.state.shippingMethods;
const defaultMethod = this.state.defaultMethod;
return (
<aside id="checkout" className="block col-1">
<h1>Shipping</h1>
<div className="row">
<select id="comboMethod" onChange={this.setShippingMethod.bind(this)} value={defaultMethod === null ? null : defaultMethod.trim()}>
{shippingMethods.map(method => { return <option key={method.shipmthd.trim()} value={method.shipmthd.trim()}>{method.shipmthd.trim()}</option>} )}
</select>
</div>
</aside>
);
}
}
export default ShippingBlock;
Whenever I try to change the select
in ShippingBlock
my function onChange
runs and the console log shows the correct selected value, but somehow the value gets set right back to the default. I haven't been able pinpoint what I have done wrong. Any tips or help would be appreciated.
UPDATE
import React from 'react';
import "./Checkout.scss"
import AddressBlock from './AddressBlock';
import PaymentBlock from './PaymentBlock';
import ShippingBlock from './ShippingBlock';
import TotalsBlock from './TotalsBlock';
import { Modal, ModalHeader, ModalBody } from 'reactstrap';
class CheckoutModal extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'React',
shippingMethod: null
};
}
setShippingMethod(method) {
this.state.shippingMethod = method;
}
render() {
const buttonStyles = {
position: "absolute",
top: "-35px",
right: "10px",
border: "0",
background: "none"
};
return (
<Modal id="checkout"
isOpen
size='xl'>
<button onClick={this.props.onRequestClose} style={buttonStyles}>x</button>
<ModalHeader className="header">
Checkout
</ModalHeader>
<ModalBody>
<div className="row">
<AddressBlock />
<ShippingBlock setShippingMethod={this.setShippingMethod.bind(this)} shippingMethod={this.state.shippingMethod}/>
</div>
<div className="row">
<PaymentBlock />
<TotalsBlock />
</div>
</ModalBody>
</Modal>
);
}
}
export default CheckoutModal;
This is what I had before. It behaves the same.
CodePudding user response:
What you've done wrong is that shippingMethod
is not part of the parent component state.
You have defined it inside the render function, which runs everytime the parent component is rendered. This means that the value you set in there will reset back to what it was previously before the child is rendered i.e. null
, therefore the child component will get the null
when it is rendered.
Solution
Move the variable into the parent's state, and make the setter a member of the parent class.
Your setShippingMethod
should be using this.setState
(similar to the useState
hook in functional components):
setShippingMethod(method) {
this.setState(state => ({...state, shippingMethod: method}));
}