【问题标题】:How to change props to state in React Hooks?如何在 React Hooks 中将 props 更改为 state?
【发布时间】:2019-06-05 10:57:23
【问题描述】:

在 Simple react 类组件中,我们曾经将 props 更改为这样的状态:

constructor(props) {
    super(props)

    this.state = {
      pitch: props.booking.pitch,
      email: props.booking.email,
      firstName: props.booking.firstName,
      arrivalDate: props.booking.arrivalDate
    }
} 

但我不知道如何在 Hooks 的新功能中做到这一点,但我正在尝试这样做。

const GenerateDescHook = ({ description: initialDesc }) => {
  const [description, setDescription] = useState(null)

useEffect(() => {
    setDescription(initialDesc)
  }, {})

 function handleChangeVariance(newVariance) {
    setDescription({
      ...description,
      template: {
        ...description.template,
        variance_name: newVariance,
      },
    })
  }

}

基本上,我只需要更改描述道具,这些道具来自另一个父组件以转换为状态。请问,你能告诉我如何以 Hooks 的新方式来做吗?

【问题讨论】:

  • 这里的第一个问题是您正在将道具复制到本地状态。为什么有必要这样做?

标签: reactjs react-hooks


【解决方案1】:

您的代码中的问题在于{}。 UseEffect 挂钩期望和数组,而不是对象。请改用[initialDesc]

这是在 props 更改时重置组件状态的方式

const GenerateDescHook = ({ description: initialDesc }) => {
  const [description, setDescription] = useState(null)

  useEffect(() => {
    setDescription(initialDesc)
  }, [initialDesc]);
}

这是您在第一次渲染时将组件状态初始化为 prop 值的方式

const GenerateDescHook = ({ description: initialDesc }) => {
  const [description, setDescription] = useState(initialDesc);
}

【讨论】:

  • 这是处理属性值外部变化的正确答案。没有这个就不会同步
  • 这个!我有一个 pageNumber 在外部发生变化的组件,useState(props.initialPageNumber) 由于一些 React 隐藏优化,不会使用最新值。即使这是页面的两个不同位置中的两个不同的组件实例。一个是initialPageNumber={1},另一个是initialPageNumber={3}
【解决方案2】:

您可以将初始状态作为第一个参数传递给useState,如下所示:

const GenerateDescHook = ({ description: initialDesc }) => {
  const [description, setDescription] = useState(initialDesc)

  ...

【讨论】:

  • 抱歉,没有帮助
  • @Feruza 这实际上是应该这样做的,这是你的类组件的钩子对应物。如果它对你不起作用,你可能做错了什么。
  • 值得注意的是,这只有在传递给GenerateDescHook 组件的description 属性永远不会更改并且OP 中的代码具有相同缺点的情况下才适用。除非你能保证(这是一个危险的假设 IMO),this 可能是更好的答案。
  • @Feruza 你为什么接受这个答案?如果父状态发生变化,子状态将保持不变。票数更多的 useEffect 解决方案,至少是我来这里的目的。
【解决方案3】:

你的状态的初始值是传递给useState的那个:

const GenerateDescHook = ({ description: initialDesc }) => {
  const [description, setDescription] = useState(initialDesc)

正如documentation 所说:

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

相当于:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

【讨论】:

  • 如何获取状态对象?不仅仅是一个单独的道具
  • 状态对象是什么意思?包含您的值的变量是description。并且钩子没有任何包含所有状态值的父变量
【解决方案4】:

很难实现依赖于 prop 值的状态,同时避免不必要的重新渲染。

这是我创建这样一个钩子的尝试:

/**
 * Replacement for useState which depends on prop value and avoids unnecessary re-renders.
 */
export function useStateBasedOnProps(propValue) {
    const [, update] = useState(false);

    const [state, setState] = useMemo(() => {
        const state = {};
        return [
            state,
            (value) => {
                if (value instanceof Function) {
                    state.value = value(state.value);
                } else {
                    state.value = value;
                }
                update((tick) => !tick);
            }
        ];
    }, [update]);

    if (state.prevPropValue !== propValue) {
        state.prevPropValue = propValue;
        state.value = propValue;
    }

    return [state.value, setState];
}

这是一个用法示例:

function IncButton({initialValue}) {
    const [value, setValue] = useStateBasedOnProps(initialValue);
    const increment = useCallback(() => setValue((prev) => prev + 1), [setValue]);
    return <button onClick={increment}>Click to increment: {value}</button>;
}

完整示例:https://gist.github.com/mdevils/b861610780300784292194f65886517a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-02
    • 2018-12-04
    • 1970-01-01
    • 2022-01-11
    • 2018-09-25
    • 2016-10-17
    • 2019-06-23
    • 1970-01-01
    相关资源
    最近更新 更多