【问题标题】:Why isn't child component re-rendered even though parent state is updated using hooks为什么即使使用钩子更新父状态,子组件也不重新渲染
【发布时间】:2020-05-02 10:53:59
【问题描述】:

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

这是我的代码。

'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 事件处理程序,并尝试使用 props 将值传递给子组件。

问题是当我要更改“数字”时,“数字”输入元素根本没有改变。 (根本没有渲染)。因此该输入元素始终具有“初始值”。 您能就此提出建议吗?

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

提前致谢。

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案1】:

    反应的哲学之一是状态是不可变的。即,您不会更改现有状态对象的属性,而是创建一个新状态对象。这允许 react 告诉通过简单的=== 检查前后的状态发生了变化。

    这行代码改变了现有的表单对象,然后将其传递给 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
    })
    

    【讨论】:

      【解决方案2】:

      尝试用

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

      【讨论】:

        猜你喜欢
        • 2019-11-24
        • 1970-01-01
        • 1970-01-01
        • 2021-12-01
        • 2021-04-06
        • 1970-01-01
        • 2022-06-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多