组件开发-数据流向

217 阅读1分钟

组件开发-数据流向

管控组件 UI 状态的数据,一般可以由内部控制,或者由父级控制。

举例有开发同学设计的组件,管控组件 UI 状态的数据,即来自于内部又来自于父级。即组件内部 watch 父级传递的数据,如果有变化,然后覆盖或合并到内部的数据中。

这样违背了单向数据流的原则,如果出现问题,不易追踪。也不易管理数据。

数据来源于父级

React Demo 为例。

子组件

const Child = ({ value, onChange }) => {
  return <input value={value} onChange={(e) => onChange(e.target.value)} />;
};

export default Child;

父级组件

import { useState } from 'react';
import Child from './Child';

const Parent = () => {
  const [value, setValue] = useState(0)

  return <>
    父级控制状态:{value}
    <div>
      <Child value={value} onChange={setValue} />
    </div>
  </>
}

export default Parent

组件内部管控数据

import { useState } from 'react';

const Child = ({ onChange: propsOnChange }) => {
  const [value, setValue] = useState();

  const onChange = (e) => {
    const newV = e.target.value;
    setValue(newV);
    propsOnChange && propsOnChange(newV);
  };

  return <input value={value} onChange={onChange} />;
};

export default Child;

父级组件

import { useState } from 'react';
import Child from './Child';

const Parent = () => {
  const [value, setValue] = useState()

  return <>
    组件控制状态:{value}
    <div>
      <Child onChange={setValue} />
    </div>
  </>
}

export default Parent

更复杂的场景

相对以上的场景,下面增添了其它的特性:

  1. 增加默认值 defaultValue
  2. 管控组件 UI 状态的数据,可以来自于父级或来自于内部
import { useState } from 'react';

const Child = ({
  value: propsValue,
  defaultValue,
  onChange: propsOnChange,
}) => {
  // 关于 defaultValue 需要注意的是,只消费一次
  const [value, setValue] = useState(defaultValue || '');

  const onChange = (e) => {
    const newV = e.target.value;
    // 如果数据来自于父级,则不更新 value
    propsValue === undefined && setValue(newV);
    propsOnChange && propsOnChange(newV);
  };
  
  const props = {
      value: propsValue !== undefined ? propsValue : value,
      onChange
  }

  return <input {...props} />;
};

export default Child;

父级组件

import { useState } from 'react';
import Child from './Child';

const Parent = () => {
  const [value, setValue] = useState()
  const [componentValue, setComponentValue] = useState()

  const onChange = (e) => {
    const newV = e.target.value;
    setValue(newV);
    propsOnChange && propsOnChange(newV);
  };

  return <>
    父级控制状态:{value}
    <div>
      <Child value={value} onChange={setValue} />
    </div>
    组件控制状态:{componentValue}
    <div>
      <Child onChange={setComponentValue} />
    </div>
  </>
}

export default Parent