【问题标题】:React useState hook not triggering re-render of child componentReact useState钩子不会触发子组件的重新渲染
【发布时间】:2020-01-26 03:13:14
【问题描述】:

我有一个父功能组件<EditCard/>,它是在选择编辑表行按钮时打开的模式。此编辑卡包含一个名为data 的状态变量,其中包含正在编辑的表格行中的数据。我正在使用useState 钩子设置/修改<EditCard/> 的状态。

<EditCard/> 有一个子组件 <CategoryDropdown/>,它是一个下拉列表,接受一个 prop data.assignCategory 作为其选定值和一个回调 handleChange(),它使用从下拉列表中选择的值更新状态值 data

当我从下拉列表中选择一个新值时,handleChange() 被调用,setData() 被调用,我看到状态正在更新,但 <CategoryDropdown/> 没有使用新选择的值重新呈现。

EditCard 组件代码

export default function EditCard(props) {
    const [data, setData] = useState(props.data);

    const handleChange = () => event => {
        let d = data;
        d.assignCategory = event.target.value;
        setData(d);
    };

    let assignCategoryCol = data.assignCategory !== undefined ? <AssignCategoryCol data={data} handleChange={handleChange}/> : <></>;

    return (
        <div>
            {assignCategoryCol}
            <Button>Update</Button>
        </div>
    )
}

{props.data.bucketTotal}`} <Lock/></Typography>)
};

const AssignCategoryCol = (props) => {
    return (
        <CategoryDropdown id={props.data.id} assignedCategory={props.data.assignCategory} handleDropdownChange={props.handleChange}/>)
};

const useStyles = makeStyles(theme => ({}));

CategoryDropdown 组件

class CategoryDropdown extends Component {
    constructor(props) {
        super(props);
        //TODO Get Categories from DB and set default
        this.state = {
            categories: ['Select One', 'Category1', 'Category2', 'Category3'],
        };
    }

    render() {
        return (
            <div id={'categoryDropdown'}>
                <Select onChange={this.props.handleDropdownChange(this.props.id)} value={this.props.assignedCategory}>
                    {this.state.categories.map((category) => {
                        return <MenuItem value={category}>{category}</MenuItem>
                    })}
                </Select>
            </div>
        )
    }
}


const styles = theme => ({});

export default withStyles(styles)(CategoryDropdown)

【问题讨论】:

  • React 不会知道对象中只有一个键(即存储到状态)发生了变化。您需要一起替换整个对象。通过复制处于该状态的对象(创建一个新对象),使用您要添加的值更改该对象来执行此操作。然后,将这个新对象存储到状态中。换句话说,完全替换原来的对象。

标签: javascript reactjs react-hooks


【解决方案1】:

为了让 React 知道状态发生了变化,你需要用一个全新的对象替换当前对象。目前,react 认为它是同一个对象,所以什么也不做。它不会搜索对象以查看其中是否有任何属性已更改。

在您的 handleChange 事件处理程序中,您有:

let d = data;

这不是复制数据对象。相反,现在变量“d”指向变量“data”指向的同一个对象(在内存中)。

(有关更多信息,请阅读“按引用传递”与“按值传递”)。

要解决这个问题,请参阅下面的解构/复制:

const [data, setData] = useState(props.data)

const handleChange = event => {
        let newData = {...data} //copy the object
        newData.assignCategory = event.target.value;
        setData(newData);
 };

【讨论】:

  • 我尝试了这个解决方案,但它不起作用,通过将对象或数组复制到新变量并调用相应的 setfunction 调用,但它仍然没有更新子元素
  • 这不是您简单地将其设置为一个新变量,而是您创建了一个完全不同的对象。如果我有 var A = data.然后我说 var B = data.现在,var B 指向的对象与 var A 指向的对象相同。 (查找“按引用传递”与“按值传递”以了解原因)。您确定将原始对象或数组复制为全新的对象或数组吗?
【解决方案2】:

对我来说,当setState 更新网址时,我遇到了 HTML5 视频未更新的问题。正如迈亚所说,我也已经在做上述事情了。

我的解决方法是向元素添加 key

例如

&lt;video key={ item.videoUrl } /&gt;

【讨论】:

  • 谢谢。出于某种原因,除非我有这个键,否则我的子组件之一不会重新渲染。
猜你喜欢
  • 2020-10-29
  • 2020-06-02
  • 1970-01-01
  • 2020-08-06
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-10
相关资源
最近更新 更多