我将道具传递给子组件,来自父组件,从他父母那里接收同一道具。
出于某种原因,当父道具更新时,此更新不会影响子组件。
组件本身非常基础:
这是父母:
import React, { Component } from 'react'
import styled from 'styled-components'
import { Icon } from 'antd'
import BaseProductSelector from '../BaseProductSelector'
import BaseProductPreview from '../BaseProductPreview'
import FullDesignSelector from '../FullDesignSelector'
import ColorPicker from '../ColorPicker'
import GeneratorProgress from '../GeneratorProgress'
import GeneratorError from '../GeneratorError'
import BPDetails from './BPDetails'
const GeneratorFlow = styled.div`
/*background-color: #eeeeee;*/
padding: 0 60px;
h3 {
color: #444;
}
.innerGenFlow {
padding: 15px;
border-radius: 5px;
box-shadow: 0 20px 40px -14px rgba(0, 0, 0, 0.35);
}
`
export default class ProductGeneratorFlow extends Component {
constructor(props) {
super()
let colors
if (props.product) {
colors = props.product.variations.filter(p => p.type === 'color')
} else {
colors = []
// colors.push(props.baseProduct.variations.filter(p => p.type === 'color')[0])
}
this.state = {
pickedColors: colors,
done: false,
error: false,
}
this.setStep = this.setStep.bind(this)
this.setKey = this.setKey.bind(this)
this.showBP = this.showBP.bind(this)
this.hideBP = this.hideBP.bind(this)
this.onChange = this.onChange.bind(this)
this.toggleColor = this.toggleColor.bind(this)
this.toggleAll = this.toggleAll.bind(this)
this.productCreated = this.productCreated.bind(this)
this.productPending = this.productPending.bind(this)
this.setFirstColor = this.setFirstColor.bind(this)
this.displayError = this.displayError.bind(this)
}
setStep(step) {
this.setState({ step })
}
showBP() {
this.setState({ BPDisplayed: true })
}
hideBP() {
this.setState({ BPDisplayed: false })
}
getBaseProd() {
const bpid = this.props.product.supplierBaseProductId
const result = this.props.base_products.filter(obj => obj._id === bpid)
return result[0]
}
setKey(activeKey) {
this.setState({
activeKey,
})
}
onChange(activeKey) {
this.setState({
activeKey,
})
}
productPending() {
this.setState({
done: false,
error: false,
})
this.props.showBP()
}
productCreated() {
this.props.displaySuccess()
this.setState({ done: true })
}
displayError() {
this.setState({ error: true })
}
toggleColor(color) {
let pickedColors = this.state.pickedColors
if (this.state.pickedColors.includes(color)) {
// console.log(pickedColors.filter(i => i != color).length)
pickedColors = pickedColors.filter(i => i != color)
} else {
pickedColors.push(color)
}
this.setState({
pickedColors,
})
}
test(id) {
this.setState({picked: true})
this.props.select(id)
}
toggleAll(value) {
if (value === true) {
this.setState({
pickedColors: this.props.baseProduct.variations.filter(p => p.type === 'color'),
})
} else {
this.setState({ pickedColors: [] })
}
}
setFirstColor() {
if (this.state.pickedColors.length > 0) {
this.props.setVariation(this.state.pickedColors[0])
}
}
render() {
if (this.state.error) {
return (
<GeneratorError
showBP={this.props.showBP}
reset={this.productPending}
/>
)
}
if (this.state.done) {
return (
<GeneratorProgress
active
showBP={this.props.showBP}
reset={this.productPending}
/>
)
}
if (this.props.product) {
return (
<GeneratorFlow>
<FullDesignSelector
designs={this.props.designs}
select={this.test}
addedDesigns={this.props.addedDesigns}
getImage={this.props.getImage}
removeDesign={this.props.removeDesign}
active
printingZone={this.props.printingZone}
setStep={this.setStep}
showBP={this.showBP}
showDS={this.props.showDS}
setKey={this.setKey}
/>
<ColorPicker
baseProduct={this.props.baseProduct}
product={this.props.product}
picked={this.state.pickedColors}
toggleColor={this.toggleColor}
variation={this.props.variation}
selectAll={this.toggleAll}
toggleFirstColor={this.props.toggleFirstColor}
setVariation={this.props.setVariation}
selectedColor={
this.props.variation ? this.props.variation.value : null
}
setPreviewColor={this.props.setVariation}
/>
<BaseProductPreview
addedDesigns={this.props.addedDesigns}
size={this.props.size}
shop={this.props.shop}
printingZone={this.props.printingZone}
picked={this.state.pickedColors}
previews={this.props.previews}
product={this.props.product}
setDone={this.productCreated}
baseProduct={this.getBaseProd()}
displaySuccess={this.props.displaySuccess}
generatorError={this.displayError}
status='edition'
setKey={this.setKey}
products={this.props.products}
productLoading={this.props.productLoading}
/>
</GeneratorFlow>
)
}
return (
<GeneratorFlow>
<ColorPicker
picked={this.state.pickedColors}
toggleColor={this.toggleColor}
baseProduct={this.props.baseProduct}
toggleFirstColor={this.setFirstColor}
variation={this.props.variation}
selectAll={this.toggleAll}
setVariation={this.props.setVariation}
selectedColor={
this.props.variation ? this.props.variation.value : null
}
setPreviewColor={this.props.setVariation}
/>
<FullDesignSelector
designs={this.props.designs}
select={this.props.select}
addedDesigns={this.props.addedDesigns}
getImage={this.props.getImage}
printingZone={this.props.printingZone}
removeDesign={this.props.removeDesign}
active
setStep={this.setStep}
showBP={this.showBP}
showDS={this.props.showDS}
setKey={this.setKey}
/>
<BaseProductPreview
addedDesigns={this.props.addedDesigns}
baseProduct={this.props.baseProduct}
generatorError={this.displayError}
size={this.props.size}
displaySuccess={this.props.displaySuccess}
shop={this.props.shop}
picked={this.state.pickedColors}
setDone={this.productCreated}
printingZone={this.props.printingZone}
previews={this.props.previews}
setPreview={this.props.setPreview}
status='creation'
setStep={this.setStep}
products={this.props.products}
productLoading={this.props.productLoading}
/>
</GeneratorFlow>
)
}
}
这是在孩子中使用这个道具的唯一部分
import React, { Component } from 'react'
import styled from 'styled-components'
import toPx from 'unit-to-px'
import _ from 'lodash'
import { LocalForm, Control } from 'react-redux-form'
import { withRouter } from 'react-router-dom'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { toast } from 'react-toastify'
import { Input, Select, Icon, Tooltip } from 'antd'
import s3 from '../../../../../services/s3'
import theme from '../../../../../theme/theme'
import Alert from '../../../../../components/Alert'
import { createProduct, modifyProduct } from '../../../../../modules/products'
// import ProductImage from '../../../../../components/ProductImage'
class BaseProductPreview extends Component {
constructor(props) {
super(props)
let colors
if (props.product) {
colors = Object.assign([], props.product.variations.filter(v => v.type === 'color'))
} else {
colors = []
}
this.state = {
name: props.product ? props.product.name : '',
displayDescription: props.product ? Object.assign({}, props.product.displayDescription) : {},
collections: (props.product && props.product.collections) ? props.product.collections : [],
pricing: props.product ? Object.assign({}, props.product.pricing) : { margin: 0 },
elevdone: false,
i: 0,
colors,
}
this.createInnerProduct = this.createInnerProduct.bind(this)
this.getPrice = this.getPrice.bind(this)
}
oneColor() {
if (this.props.baseProduct.variations && this.state.colors) {
let colorAlert
if (this.state.colorAlertShown) {
colorAlert = <Alert message='Choisissez au moins une couleur' type='error' />
}
const colorsBp = this.props.baseProduct.variations.filter(v => v.type === 'color')
if (colorsBp.length <= 1) {
return ''
}
return (
<div>
<p>Choix de couleur :</p>
{ colorAlert }
<span
className='bullet-color'
>
{this.getColorsRef(this.props.baseProduct).map(value =>
(<div
onClick={() => { this.toggleColor(value) }}
className={this.colorIsInProduct(value)}
style={{ backgroundColor: value }}
/>))}
</span>
</div>)
}
return null
}
getColorsRef() {
return this.props.baseProduct.variations.filter(v => v.type === 'color').map(a => a.value)
}
colorIsInProduct(couleur) {
// true/false
let active
if (this.state.colors.find(v => v.value === couleur)) {
active = 'active-color'
}
return active
}
toggleColor(couleur) {
// const item = this.state.item
const colors = this.state.colors
// si on a deja la couleur dans le produit on l'enlève
if (colors.find(v => v.value === couleur) && colors.length > 1) {
// je retire cette couleur des varaitions de mon produits
const index = colors.indexOf(colors.find(v => v.value === couleur))
colors.splice(index, 1)
} else if (colors.find(v => v.value === couleur)) {
this.setState({ colorAlertShown: true })
} else {
// on va chercher la variation couleur corespondante
// dans le base product et on la copie dans le product
this.setState({ colorAlertShown: false })
colors.push(this.props.baseProduct.variations.find(v => v.value === couleur))
}
this.setState({ colors })
// TODO on change la couleur du mockup
}
getJsonsObjects(printingZones) {
// INITIATE EMPTY JSON OBJECT
const jsonsArray = {}
// GET CURRENT CANVAS
printingZones.map((item) => {
const y = document.getElementById(`${item}-canvas`).fabric
const helper = _.filter(y.getObjects(), { clipFor: 'layer' })[0]
if (helper) {
helper.set({ stroke: 'transparent' })
}
jsonsArray[item] = y.toJSON(['height'])
})
return jsonsArray
}
getCustomizationPrice() {
let customizationPrice = 0
Object.keys(this.props.baseProduct.printingZone).map((item) => {
const y = document.getElementById(`${item}-canvas`).fabric
const items = y.getObjects()
if (items.length > 1) {
customizationPrice = customizationPrice + 5
}
})
customizationPrice = customizationPrice - 5
if (customizationPrice < 0) {
customizationPrice = 0
}
return customizationPrice
}
getAction() {
return (<p>Créer mon produit</p>)
}
marginValidation(value) {
let returned_value = value
if (value == '') {
returned_value = 0
}
if (!value) {
returned_value = 0
} else if (value > 100) {
// TODO Show moreThan100Alert
returned_value = 100
}
const pricing = Object.assign({}, this.state.pricing, { margin: returned_value })
this.setState({ pricing })
}
validForm() {
if (this.state.name && this.props.picked.length > 0 && this.state.pricing.margin >= 0 && this.props.addedDesigns.length > 0) {
return false
}
return true
}
getPrice() {
const position_print = this.props.addedDesigns.map(d => {
return d.position
})
// uniq(position_print)
const count = []
position_print.map((position) => {
if (count.indexOf(position) === -1) {
count.push(position)
}
})
if (count.length <= 1) {
return (
<div>
<p className='price'>Cout de production <span>{this.props.baseProduct.unitPrice} €</span></p>
<div className='price-marge'>Vos bénéfices <span className='requiredField2'>*</span>
<Control.text
component={Input}
className='inputMarge'
model='.margin'
value={this.state.pricing.margin}
onChange={(e) => {
this.marginValidation(e.target.value.replace(',', '.'))
}}
/>
</div>
<hr />
<div className='price-total'>
{`
${parseFloat(this.props.baseProduct.unitPrice)
+
parseFloat(this.state.pricing.margin)} €`}
</div>
</div>
)
}
if (count.length > 1) {
return (
<div>
<p className='price'>Cout de production <span>{this.props.baseProduct.unitPrice} €</span></p>
<p className='price'>Impression supplémentaire <span>5 €</span></p>
<div className='price-marge'>Vos bénéfices <span className='requiredField2'>*</span>
<Control.text
component={Input}
className='inputMarge'
model='.margin'
value={this.state.pricing.margin}
onChange={(e) => {
this.marginValidation(e.target.value.replace(',', '.'))
}}
/>
</div>
<hr />
<div className='price-total'>
{`
${parseFloat(this.props.baseProduct.unitPrice)
+
parseFloat(this.state.pricing.margin) + parseFloat(5)} €`}
</div>
</div>
)
}
return null
}
getCategory() {
if (this.props.baseProduct.category.fr[0] === 'Homme' && this.props.baseProduct.category.fr[1] === 'Femme') {
return (<span>Unisex</span>)
}
if (this.props.baseProduct.category.fr[0] === 'Homme') {
return (<span>Homme</span>)
}
if (this.props.baseProduct.category.fr[0] === 'Femme') {
return (<span>Femme</span>)
}
return null
}
showElevio() {
if (this.state.i < 5) {
this.state.i = this.state.i + 1
setTimeout(() => {
if (this.props.productLoading.loading === true || this.props.products.length === 0) {
if (this.props.products.length === 0 && this.state.elevdone === false) {
return (
window._elev.openArticle(263),
this.setState({ elevdone: true })
)
} return null
}
if (this.props.productLoading.loading === false) {
this.showElevio()
}
return null
}, 500)
} return null
}
render() {
const { Option } = Select
const children = []
if (this.props.shop.settings.collections) {
this.props.shop.settings.collections.map((collec, i) => {
children.push(<Option key={collec.name ? collec.name : i}>{collec.name}</Option>)
return null
})
}
this.showElevio()
return (
<StyledBaseProductPreview>
<h2>Description</h2>
<LocalForm
onSubmit={() => this.createInnerProduct()}
>
<div className='form-step'>
<p className='advice-name'>
<Tooltip title='Figurera sur la fiche produit'>
<span>{this.props.baseProduct.subCategory.fr} {this.getCategory()}</span>
</Tooltip>
</p>
<p>Nom <span className='requiredField'>*</span></p>
<Control.text
component={Input}
model='.name'
placeholder='Nom du produit'
value={this.state.name}
onChange={(e) => {
this.setState({ name: e.target.value })
}}
/>
</div>
<div className='form-step'>
<p>Description</p>
<Control.textarea
className='productDescription'
model='.displayDescription'
placeholder='Description du produit'
value={this.state.displayDescription.fr}
onChange={(e) => {
const new_item = Object.assign({}, this.state.displayDescription)
new_item.fr = e.target.value
this.setState({ displayDescription: new_item })
}}
/>
</div>
<div className='form-step'>
<p>Collection(s)</p>
<Select
mode='multiple'
className='styledSelect'
placeholder='Pas de collection'
notFoundContent='Pas de collection'
value={this.state.collections}
style={{ width: '100%' }}
onSearch={(e) => {
this.setState({ toCreate: e })
}}
onChange={(e) => {
this.setState({ collections: e })
}}
>
{children}
</Select>
</div>
<div className='form-step pricingForm'>
<h2>Prix </h2>
<hr />
{this.getPrice()}
</div>
<Crumpet type='submit' className='superCrumpet' disabled={this.validForm()}>
{this.getAction()}
</Crumpet>
</LocalForm>
</StyledBaseProductPreview>
)
}
}
const mapStateToProps = (state, ownProps) => {
console.log(state); // state
console.log(ownProps); // undefined
return({
user: state.user,
addedDesigns: ownProps.addedDesigns,
})
}
const mapDispatchToProps = dispatch => bindActionCreators({
createProduct,
modifyProduct,
}, dispatch)
export default connect(
mapStateToProps,
mapDispatchToProps,
)(BaseProductPreview)
检查这些元素时,我可以看到父级正在更新:
现在,有趣的是:当父道具更新时,前两个子组件道具也会更新,但BaseProductPreview不会更新!
但是,只要更改子组件的状态,就会立即更新。
怎么会这样?状态如何更新组件道具?
答案 0 :(得分:0)
React只对不在道具上的状态起作用。每当您更改状态UI时,都会使用最新更改进行更新将您的道具绑定到子组件中的状态,并使用componentWillReceiveProps(props)在父组件中更新道具时更改子状态。
答案 1 :(得分:0)
我找到的唯一解决方案是将更高的组件与redux连接起来,这样就不会有任何子项与redux相关,然后通过props将reducer函数传递给那个孩子。
如果没有redux,我的组件会正确更新。