繁体   English   中英

如何指定带有功能组件的构造函数(粗箭头语法)?

[英]How to specify a constructor with a functional component (fat arrow syntax)?

鉴于此组件:

import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'

const NewGoalInput = props => {
  return (
    <input type="text" onKeyUp={handleKeyUp}/>
  )
}

const handleKeyUp = (e) => {
  if (e.key === "Enter") {
    // TODO Add goal
  }
}

export default NewGoalInput

如何在不使用extends React.Component语法的情况下添加可以定义 state 的构造函数?

由于它是一个无状态组件,它没有组件生命周期。 因此你不能指定一个constructor

你必须扩展React.Component来创建一个有状态的组件,然后它需要一个构造函数,你将能够使用state

更新自从React 16.8.0和 Hooks 引入以来,有更多选择。

Hooks 是一个新的特性提案,它可以让你在不编写类的情况下使用状态和其他 React > 特性。 它们作为 > v16.8.0 的一部分在 React 中发布

无国籍:

import React from "react"

const Stateless = ({name}) => (
  <div>{`Hi ${name}`}</div>
);

有状态:

可以访问组件生命周期方法和本地状态。

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

  componentDidMount() {
    const { count } = this.state;
    document.title = `You've clicked ${count} times.`;
  }

  componentDidUpdate() {
    const { count } = this.state;
    document.title = `You've clicked ${count} times.`;
  }

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

使用钩子:

能够使用State HookEffect Hook

如果您熟悉 React 类的生命周期方法,您可以将 useEffect Hook 视为 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。

import React, { useState, useEffect } from "react";

const UsingHooks = () => {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You've clicked ${count} times.`;
  });

  return (
    // <> is a short syntax for <React.Fragment> and can be used instead of a wrapping div
    <>
      <p>You've clicked {count} times.</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </>
  );
}

现在我们有了useState和 hooks,答案有点过时了。 我遇到这个问题是因为我做错了什么。 这是我正在做的一些简化代码。

// set an initial state
const [ value, setValue ] = useState(0)

// gets called after component is re-rendered
useEffect(() => {
   // callback to parent that set props
   props.update()
})

// if we have an existing value passed in
if (props.value) {
   setValue(props.value)
}

这段代码使用钩子从有状态类转换为函数,最初在构造函数中设置默认道具 - 但函数没有构造函数,每次组件重新渲染时都会进行检查:

  1. 调用useState
  2. 触发重新渲染
  3. useEffect 被触发
  4. 调用 parent 来设置 props
  5. props 更新,所以 child 再次渲染
  6. 转到 1

如您所见,这会导致无限循环。 解决方案真的很简单。 这是与原始版本的模拟差异。

- const [ value, setValue ] = useState(0)
+ const [ value, setValue ] = useState(props.value || 0)

- if (props.value) {
-   setValue(props.value)
- }

基本上,只需从 props 初始化状态,不要做诸如调用useState类的愚蠢事情,除非响应某种类型的事件或回调。

你没有。 您示例中的组件类型称为“无状态功能组件”。 它没有状态,也没有生命周期方法。 如果您希望组件有状态,则必须将其编写为类组件。

要模拟 FC 中的构造函数,请使用 useEffect。

useEffect(() => {
  ... here your init code
}, []);

就是这样! EZ! 这个 useEffect 在组件加载时只运行一次,之后再也不运行,只是不要忘记在最后添加方括号。

您可以将 useState 设置为功能组件内的第一行,并添加一个函数作为“初始值”:

const MyComponentName = props => {
  useState(() => {
    console.log('this will run the first time the component renders!');
  });
  return <div>my component!</div>;
};

您可以使用useMemo钩子(如下)来演示作为功能组件的构造函数。 有人建议使用useEffect它会在渲染后调用。

useMemo(() => {
  console.log('This is useMemo')
}, []);

对于那些想安装组件之前运行一次函数的人,这里有一个钩子(用 TypeScript 编写)。

通常useEffectuseLayoutEffect就足够了,但它们在组件安装后运行,有时您希望在此之前运行代码(如构造函数)。

import React, { useRef } from "react";

function useOnce<Type>(callBack: () => Type): Type {
  const result = useRef<Type | null>(null);

  if (result.current !== null) {
    return result.current;
  }

  result.current = callBack();
  return result.current;
}

const Component: React.FC<{}> = () => {
  const result = useOnce(() => {/* Code you would normally put in a constructor */});

  return <div />
}

或者,您可以使用react-afc

import { afc, reactive } from 'react-afc'

function heavyCalc() {/*...*/}

const Conponent = afc(props => {
  // Called once, before the first render

  const state = reactive({
    name: 'Stack',
    inputsCount: 0
  })

  // Without useMemo(..., [])
  const result = heavyCalc()

  // The function is created once and does not cause
  // a re-render of child components
  function onInput(e) {
    state.inputsCount++
    state.name = e.currentTarget.value
  }

  // Saved between renders (no longer need useRef)
  let rendersCount = 0

  // Must return the render-function
  return () => {
    // The function works like a regular react-component
    // Here you can use the usual hooks
    rendersCount++
    return (
      <input onChange={onInput} value={state.name}/>
    )
  }
})

package 具有使用state (包括redux )、 Z541EF72F67F6B7B8生命周期方法3452C80DACC84B8的必要方法

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM