【发布时间】:2021-09-01 00:11:10
【问题描述】:
我有一个父组件和一个子组件。子组件最初将数据呈现到表单中,但在更改数据时,子组件不会更新。
父组件:
import React from 'react'
import { connect } from 'react-redux'
import styles from '../styles'
import ExpressionsForm from './expressionsForm'
class EditCondition extends React.Component {
constructor (props) {
super(props)
this.state = {
condition: null
}
this.updateExpression = this.updateExpression.bind(this)
this.changes = false
}
componentWillMount () {
let conditionid = this.props.data.id
let condition = this.props.conditions.find(c => {
return (c.id = conditionid)
})
this.setState({ condition })
}
updateExpression (e) {
let expressionid = e.currentTarget.dataset.expressionid
let field = e.currentTarget.dataset.field
let value = e.target.value
let condition = this.state.condition
let expression = condition.expressions[expressionid]
expression[field] = value
condition.expressions[expressionid] = expression
this.changes = true
this.setState({ condition })
console.log('updateExpression condition: ', condition)
}
render () {
let condition = this.state.condition
if (!this.state.condition) {
return (
<div>
The selected condition with ID "{this.props.data.id}" did not load. It
may not exist. Refresh and try again.
</div>
)
}
let groupOptions = this.props.gambitGroups.map(g => {
return (
<option value={g.id} key={'group' + g.id}>
{g.name}
</option>
)
})
console.log('RENDER editCondition: ', condition) // <-- Note: This always logs as expected
let expressionsJSX = condition.expressions.map((expression, i) => {
expression.id = i
console.log('expression: ', expression) // <-- Note: This always logs as expected
return (
<ExpressionsForm
key={'expressionsForm_' + i}
expression={expression}
deleteExpression={this.deleteExpression}
updateExpression={this.updateExpression}
updateExpressionData={this.updateExpressionData}
/>
)
})
return (
<table>
<thead>
<tr>
<th {...styles.modal.tableHeaderLeftAlign}>
Device & Data Point
</th>
<th {...styles.modal.tableHeaderLeftAlign}>Operator</th>
<th {...styles.modal.tableHeaderLeftAlign}>Value</th>
<th {...styles.modal.tableHeaderLeftAlign}>PlateValue</th>
<th {...styles.modal.tableHeaderLeftAlign}> </th>
</tr>
</thead>
<tbody>{expressionsJSX}</tbody>
</table>
)
}
}
export default connect(
(state, ownProps) => ({
user: state.user,
users: state.users,
gambitGroups: state.gambitGroups,
// deviceGroups: state.deviceGroups,
conditions: state.conditions,
reactions: state.reactions,
setEditMode: ownProps.setEditMode,
navByName: ownProps.navByName
}),
dispatch => ({
addImage: file => dispatch({ type: 'UPDATE_CONDITION_LOGO', file }),
updateCondition: condition =>
dispatch({ type: 'UPDATE_CONDITION', condition })
})
)(EditCondition)
和子组件:
import React from 'react'
import { connect } from 'react-redux'
import styles from '../styles'
class ExpressionsForm extends React.Component {
constructor (props) {
super(props)
this.state = {}
this.updateExpression = this.updateExpression.bind(this)
}
updateExpression (e) {
this.props.updateExpression(e)
}
render () {
let expression = this.props.expression
console.log('expression: ', expression) // Note: logs initial render only.
let data = expression.data
let deviceId = data.deviceId
let dataPointIndex = data.dataPointIndex
let operator = expression.operator
let plateValue = expression.plateValue
let value = expression.value
console.log('RENDER expressionForm: ', expression) // Note: logs initial render only
let deviceOptions = this.props.devices.map((device, i) => {
return (
<option value={device.id} key={'device_' + i}>
{device.userAssignedName}
</option>
)
})
let dataPointOptions = this.props.devices[0].inputs.map((input, i) => {
return (
<option value={input.id} key={'input_' + i}>
{input.name} currentValue: {input.value}
</option>
)
})
let operatorOptions = ['==', '!=', '<=', '>=', '<', '>'].map(
(operator, i) => {
return (
<option value={operator} key={'operator_' + i}>
{operator}
</option>
)
}
)
return (
<tr>
<td>
<select
{...styles.modal.inputSexy}
style={{ marginBottom: '20px' }}
data-field='deviceid'
data-expressionid={expression.id}
value={deviceId}
onChange={this.updateExpressionData}
>
<option value=''></option>
{deviceOptions}
</select>
<select
{...styles.modal.inputSexy}
data-field='dataPointIndex'
data-expressionid={expression.id}
value={dataPointIndex}
onChange={this.updateExpressionData}
>
<option value=''></option>
{dataPointOptions}
</select>
</td>
<td>
<select
{...styles.modal.inputSexy}
style={{ width: '75px' }}
data-field='operator'
data-expressionid={expression.id}
value={operator}
onChange={this.updateExpression}
>
<option value=''></option>
{operatorOptions}
</select>
</td>
<td>
<input
{...styles.modal.inputSexy}
style={{ width: '50px' }}
data-field='value'
data-expressionid={expression.id}
value={value}
onChange={this.updateExpression}
/>
</td>
<td>
<input
{...styles.modal.inputSexy}
style={{ width: '88px' }}
data-expressionid={expression.id}
data-field='plateValue'
value={plateValue}
onChange={this.updateExpression}
/>
</td>
<td>
<i className='fa fa-close'
data-expressionid={expression.id}
onClick={this.deleteExpression}
></i>
</td>
</tr>
)
}
}
export default connect(
(state, ownProps) => ({
user: state.user,
users: state.users,
devices: state.devices,
gambitGroups: state.gambitGroups,
// deviceGroups: state.deviceGroups,
conditions: state.conditions,
reactions: state.reactions,
setEditMode: ownProps.setEditMode,
navByName: ownProps.navByName
}),
dispatch => ({
addImage: file => dispatch({ type: 'UPDATE_XXX', file })
})
)(ExpressionsForm)
我在 redux 存储中有一个对象数组,称为条件。父组件获取这些条件之一的 ID,找到正确的条件,并通过 componentWillMount 将其加载到状态以供用户修改。条件上有一个对象数组,称为表达式。这些表达式中的每一个都被传递给名为 ExpressionsForm 的子组件。
所以我们通过 map 函数遍历表达式并将生成的 JSX 作为表达式JSX 返回。
let expressionsJSX = condition.expressions.map((expression, i) => {
expression.id = i
console.log('expression: ', expression) // <-- Note: This always logs as expected
return (
<ExpressionsForm
key={'expressionsForm_' + i}
expression={expression}
deleteExpression={this.deleteExpression}
updateExpression={this.updateExpression}
updateExpressionData={this.updateExpressionData}
/>
)
})
请注意,已将表达式传递给它 expression={expression}
在子组件的渲染中你会看到
let expression = this.props.expression
console.log('expression: ', expression) // Note: logs initial render only.
由于这是一个道具,无论是控制台记录还是渲染到某个 JSX 中都无关紧要 - 当道具更改时,更改也应该重新渲染。但在这种情况下它没有这样做。为什么?
例如,我在 1 个条件下保存了 1 个表达式。它呈现时,我单击表达式的 plateValue 输入字段 - 默认情况下包含 5 - 并尝试在 5 之后添加 6。当父组件更新状态时,我会在 console.log 中看到重新呈现表达式的 plateValue 字段现在包含一个“56”……它只是不在子组件中呈现……!?
这是一个示例 console.log
初始渲染:
RENDER editCondition: {id: "1", group: 1, name: "Temperature >= 75F", 元:“如果温室中> = 75F,则打开交流电,直到温度低于5度 75F",表达式:Array(1)} editCondition.jsx:191 表达式:{data: {…},运算符:>=,值:“75”,plateValue:“5”,id:0} expressionForm.jsx:39 RENDER expressionForm: {data: {…}, operator: ">=",值:"75",板值:"5",id:0}
点击进入plateValue字段并添加一个'6',父级重新渲染......并且:
editCondition.jsx:188 RENDER editCondition: {id: "1", group: 1, name: “温度 >= 75F”,meta:“如果温室中 >= 75F,打开交流电直到 比 75F 低 5 度”,表达式:Array(1)} editCondition.jsx:191 表达式:{数据:{…},运算符:">=",值: "75", plateValue: "56", id: 0} editCondition.jsx:153 状态设置! updateExpression条件:{id:“1”,组:1,名称:“温度> = 75F”,meta:“如果温室 >= 75F,打开空调,直到 5 度冷却 大于 75F",表达式:Array(1)}
我在其中看到一个“plateValue:“56””。那么为什么不重新渲染 子组件?好困惑。
我已经尝试过 componentWillReceiveProps、componentWillUpdate 等。我什至无法让这些触发 console.log。
发生了一些我无法弄清楚的事情。我已经做 React 很长时间了,我很困惑。这种情况不再经常发生了。
提前感谢您的帮助
PS 我确实看过 getDerivedStateFromProps - 文档提供了示例非常好,但它们没有解释 props 和 state 参数实际上是什么。文档很烂。他们的解释很烂。他们的例子并没有说明它实际上做了什么。我只使用 componentWillReceiveProps 来知道道具何时发生变化,然后更新状态或其他什么。 getDerivedStateFromProps 只是让我感到困惑。尽管如此,我还是玩弄了它,也无法让它工作。
【问题讨论】:
-
唯一可行的方法是执行
let ex = Object.assign({},expression)并将ex作为值传递给表达式道具。为什么这似乎有效? -
你能做一个只关注有问题的代码部分的最小示例吗?
标签: javascript reactjs