【问题标题】:'value' from props and 'thisValue' in state, antipattern?来自道具的“价值”和状态中的“thisValue”,反模式?
【发布时间】:2019-11-01 03:26:18
【问题描述】:

我最近发现自己写了很多类似这样的代码:

const SomeComponent: React.FunctionComponent<SomeComponentProps> = props => {
  const { value } = props;
  const [thisValue, setThisValue] = React.useState(value);

  const handleChange = React.useCallback(e => {
    setThisValue(e.target.value);
  }, []);
 ....

Full example on CodePen.

我从 props 传入一个初始化值,然后在组件中修改该值。

它做我想做的事,但我开始怀疑它。

这是一种反模式吗?

【问题讨论】:

    标签: reactjs react-hooks anti-patterns


    【解决方案1】:

    这是一篇很好的(有点旧的)文章,讨论了使用 props 初始化状态:

    https://medium.com/@justintulk/react-anti-patterns-props-in-initial-state-28687846cc2e

    React 文档称这是一种反模式:

    “在 getInitialState 中使用 props 生成状态往往会导致“真实数据源”的重复,即真实数据在哪里。这是因为 getInitialState 仅在组件首次创建时才被调用。”

    从文档中,有一个例外是:

    “仅当您有意忽略道具更新时才使用此模式。在这种情况下,将道具重命名为initialColor或defaultColor是有意义的。然后您可以通过更改来强制组件“重置”其内部状态必要时它的钥匙。”

    话虽如此,我也发现自己有时会这样做。

    我发现它有用的一个例子是允许用户编辑复杂状态的组件。您可以使用 props 初始化状态,组件在内部处理对此状态的更改。如果你想在 props 改变时重置 state,你有两种选择:

    首先是监听变化,调用setState,如:

    componentDidUpdate(prevProps, prevState) {
      if (prevProps.inputValue !== this.props.inputValue) {
        this.setState({ inputVal: this.props.inputValue })
      }
    }
    

    推荐的选项是给组件一个键,该键取决于应该触发重置的道具。然后当 props 改变时,组件状态会重新初始化:

    <MyComponent initProp={someValue} key={`key_${someValue}`/>
    

    我只会推荐这些选项用于复杂的状态。在大多数示例中,父组件可以保持此状态,而内部组件可以使用回调来更新父组件的更改。

    【讨论】:

    • "但是,如果您明确指出 prop 只是组件的内部控制状态:",似乎 OP 只打算初始化 thisValue
    【解决方案2】:

    这是一个反模式的例子,你不让道具引导,只在安装或构造函数上设置状态。我正在尝试制作一个有状态的表单组件,但会在用户提交时向消费者(父级)发出信号。消费者可以选择重置表单:

    function App() {
      const [initial, setInitial] = React.useState({
        name: 'init',
      });
      const submit = React.useCallback(form => {
        console.log('form is:',form);
      }, []);
      return (
        <div>
          <button onClick={() => setInitial({ name: 'reset' })}>
            reset
          </button>
          <Form initial={initial} submit={submit} />
        </div>
      );
    }
    
    function Form({ initial, submit }) {
      const [form, setForm] = React.useState(initial);
      const onChange = React.useCallback(e => {
        const name = e.target.value;
        setForm(form => ({ ...form, name }));
      }, []);
      const onSubmit = React.useCallback(
        e => {
          e.preventDefault();
          setForm(form => {
            submit(form);
            return form;
          });
        },
        [submit]
      );
      //witout this effect reset will not work
      React.useEffect(() => setForm(initial), [initial]);
      return (
        <form onSubmit={onSubmit}>
          <input
            type="text"
            value={form.name}
            onChange={onChange}
          />
          <button type="submit">Save</button>
        </form>
      );
    }
    
    ReactDOM.render(<App />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-16
      • 2016-08-13
      • 1970-01-01
      • 2018-09-02
      • 2018-07-10
      • 1970-01-01
      相关资源
      最近更新 更多