即使使用挂钩更新了父状态,为什么子组件也没有重新渲染

时间:2020-05-02 02:42:39

标签: javascript reactjs react-hooks

我是React的新手,使用钩子时遇到了问题。 我将构建一个基本表单作为子组件,但是我想知道为什么更改其值时子表单上的输入元素未呈现。

这是我的代码。

'use strict';

function SearchForm({form, handleSearchFormChange}) {

    return (
        <div className="card border-0 bg-transparent">
            <div className="card-body p-0 pt-1">
                <div className="form-row">
                    <div className="col-auto">
                        <label className="mr-1" htmlFor="number">Number:</label>
                        <input type="text" className="form-control form-control-sm w-auto d-inline-block"
                               name="number" id="number" value={form.number} onChange={handleSearchFormChange}/>
                    </div>
                </div>
            </div>
        </div>
    );
}

function App() {
    const formDefault = {
        number: 'Initial Value'
    };
    const [form, setForm] = React.useState(formDefault);

    const handleSearchFormChange = (e) => {
        setForm(Object.assign(form, {[e.target.name]: e.target.value}));
        console.log('Handle Search Form Change', e.target.name, "=", e.target.value);
    };

    return (
        <React.Fragment>
            <div>Number : {form.number}</div>
            <SearchForm form={form} handleSearchFormChange={handleSearchFormChange} />
        </React.Fragment>
    );
}

const domContainer = document.querySelector('#root');
ReactDOM.render((
    <React.Fragment>
        <App/>
    </React.Fragment>
), domContainer);

我为父组件中的'number'元素定义了一个onChange事件处理程序,并尝试使用prop将值传递给子组件。

问题在于,当我要更改“数字”时,“数字”输入元素完全没有更改。 (完全不渲染)。因此,该输入元素始终具有“初始值”。 您能为此建议吗?

我想知道这种方法是否合理。

谢谢。

2 个答案:

答案 0 :(得分:2)

反应的哲学之一是状态是不变的。即,您不更改现有状态对象的属性,而是创建一个新的状态对象。这样可以做出反应,以通过之前和之后的简单===检查来更改状态。

这行代码会更改现有的表单对象,然后将其传递给setForm:

setForm(Object.assign(form, {[e.target.name]: e.target.value}));

所以react比较setForm之前和之后的对象,发现它们是同一对象。因此,得出的结论是什么都没有改变,因此该组件不会重新渲染。

相反,您需要制作对象的副本并在副本上进行更改。如果您习惯使用Object.assign,可以通过将一个空对象作为Object.assign的第一个参数来实现:

setForm(Object.assign({}, form, {[e.target.name]: e.target.value}));

或者,传播语法是一种制作对象的浅表副本的便捷方法:

setForm({
  ...form,
  [e.target.name]: e.target.value
})

答案 1 :(得分:1)

尝试用

替换setForm(Object.assign(form, {[e.target.name]: e.target.value}));
setForm(prevState => ({
    ...prevstate,
    [e.target.name]: e.target.value
}));