admin管理员组

文章数量:1327884

It's a mon React knowledge that having state initialized by props is bad if we don't make them in sync. This is considered fine:

import { useState, useEffect } from 'react';

export default function MyInput({ initialValue }) {
    const [value, setValue] = useState(initialValue);

    useEffect(
        () => setValue(initialValue),
        [initialValue]
    );

    return (
        <>
            <h1>The value is {value}</h1>
            <input
                type="text"
                value={value}
                onChange={event => setValue(event.target.value)}
            />
        </>
    );
}

But what if I actually don't want to update the value when initialValue changes and want to remove the useEffect() here? Is it strongly against React philosophy? It makes sense in my case, as I actually don't want to update this input value when something else changes the value passed as initialValue. I don't want users to lose their input when that happens.

How bad is it?

It's a mon React knowledge that having state initialized by props is bad if we don't make them in sync. This is considered fine:

import { useState, useEffect } from 'react';

export default function MyInput({ initialValue }) {
    const [value, setValue] = useState(initialValue);

    useEffect(
        () => setValue(initialValue),
        [initialValue]
    );

    return (
        <>
            <h1>The value is {value}</h1>
            <input
                type="text"
                value={value}
                onChange={event => setValue(event.target.value)}
            />
        </>
    );
}

But what if I actually don't want to update the value when initialValue changes and want to remove the useEffect() here? Is it strongly against React philosophy? It makes sense in my case, as I actually don't want to update this input value when something else changes the value passed as initialValue. I don't want users to lose their input when that happens.

How bad is it?

Share Improve this question asked Feb 17, 2022 at 18:25 Robo RobokRobo Robok 22.8k20 gold badges83 silver badges141 bronze badges 5
  • 1 It's totally fine to initialize state with anything, props if need be. The anti-pattern is syncing it. – Emile Bergeron Commented Feb 17, 2022 at 18:32
  • @EmileBergeron I've never heard calling having state and props in sync an anti-pattern. – Robo Robok Commented Feb 17, 2022 at 18:35
  • It's usually seen as an anti-pattern because it makes the state useless, as the prop should be used as-is. In your case, you don't have to sync the state with the prop, so that the user can update the value with an input. – Emile Bergeron Commented Feb 17, 2022 at 18:39
  • Does this answer your question? React Hooks: handle multiple inputs – Emile Bergeron Commented Feb 17, 2022 at 18:49
  • Based on your ments, I see an XY problem, where you're asking about some potential bad practice but the question should describe your situation, with a minimal reproducible example that provides more context. – Emile Bergeron Commented Feb 17, 2022 at 18:51
Add a ment  | 

2 Answers 2

Reset to default 2

In essence, there's nothing wrong with using a prop as the initial value of a state variable, AFAIK.

However, in your example you're doing something that is kind of nonsensical: You are defining a state variable which is initialized with the value of a prop, and then every time the prop updates you update your state with the same value. Regardless of whether it's an anti-pattern or not, it makes no sense - just use the prop directly, you're doing extra work for no profit. If you remove the useEffect you'll get a very valid use for a prop as an initial value of a state variable.

The question of using a derived state in React.js is often misunderstood, which this StackOverflow question proves.

In the provided code example from the question, it is unclear why a derived state is being used when the initialValue prop could be used directly. For the sake of clarity, using useEffect for this purpose would be considered an antipattern. Instead, you should check for changes yourself, as demonstrated in the React documentation

However, if the EmailInput ponent does some modification on the initialValue, such logic will unnecessarily pollute the parent ponent, if we followed the "rule of lifting state up" (Which I believe the author attempts to explain in this ment).

In this case, I would argue that the antipattern may be an acceptable choice if used sparingly. Robin Wieruch blog post where said antipattern is used.

An alternative solution is to use the key attribute (useful in this case), but this is only effective if the key and initialValue are based off different states. Otherwise, it may lead to duplicate renderings.

Example with the key attribute

// EmailInput.jsx
export default function EmailInput({ initialValue, onChange }) {
    const [value, setValue] = useState(initialValue);

    const handleChange = (event) => {
        const newValue = event.target.value;
        // do some modification on the newValue
        setValue(newValue);
        onChange(newValue); // pass value to parent
    };

    return (
        <>
            <h1>The Email is {value}</h1>
            <input type="text" value={value} onChange={handleChange} />
        </>
    );
}
// Checkout.jsx
export function Checkout() {
    const [user, setUser] = useState({
        id: 1,
        email: "[email protected]",
    });
    return (
        <>
            <EmailInput
                initialValue={user.email}
                key={user.id}
                onChange={(value) => setUser({ id: user.id, email: value })}
            />
            <button
                onClick={() => setUser({id: 2, email: "[email protected]"})}
            >
                Update user
            </button>
        </>
    );
}

本文标签: javascriptIs initial state based on props always bad in ReactStack Overflow