[英]How to specify a constructor with a functional component (fat arrow syntax)?
Given this component:鉴于此组件:
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
How do I add a constructor where I can define the state without using the extends React.Component
syntax?如何在不使用
extends React.Component
语法的情况下添加可以定义 state 的构造函数?
Since it's a stateless component it doesn't have the component lifecycle.由于它是一个无状态组件,它没有组件生命周期。 Therefor you can't specify a
constructor
.因此你不能指定一个
constructor
。
You have to extend React.Component
to create a stateful component which then will need a constructor and you'll be able to use the state
.你必须扩展
React.Component
来创建一个有状态的组件,然后它需要一个构造函数,你将能够使用state
。
Update Since React 16.8.0 and Hooks got introduced there are more options.更新自从React 16.8.0和 Hooks 引入以来,有更多选择。
Hooks are a new feature proposal that lets you use state and other React > features without writing a class.
Hooks 是一个新的特性提案,它可以让你在不编写类的情况下使用状态和其他 React > 特性。 They are released in React as a part of > v16.8.0
它们作为 > v16.8.0 的一部分在 React 中发布
Stateless:无国籍:
import React from "react"
const Stateless = ({name}) => (
<div>{`Hi ${name}`}</div>
);
Stateful:有状态:
Has access to component lifecycle methods and local state.可以访问组件生命周期方法和本地状态。
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>
);
}
}
Using Hooks:使用钩子:
Able to use State Hook
and Effect Hook
.能够使用
State Hook
和Effect Hook
。
If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
如果您熟悉 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>
</>
);
}
Now that we have useState
and hooks the answers are kind of out of date.现在我们有了
useState
和 hooks,答案有点过时了。 I came across this question because I was doing something wrong.我遇到这个问题是因为我做错了什么。 Here's some simplified code of what I was doing.
这是我正在做的一些简化代码。
// 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)
}
This code was converted from a stateful class to a function using hooks, originally setting the default props in the constructor - but functions don't have constructors and that check happens every time the component re-renders:这段代码使用钩子从有状态类转换为函数,最初在构造函数中设置默认道具 - 但函数没有构造函数,每次组件重新渲染时都会进行检查:
useState
useState
As you can see this results in an infinite loop.如您所见,这会导致无限循环。 The solution is really quite simple.
解决方案真的很简单。 Here's a mock diff from the original.
这是与原始版本的模拟差异。
- const [ value, setValue ] = useState(0)
+ const [ value, setValue ] = useState(props.value || 0)
- if (props.value) {
- setValue(props.value)
- }
Basically, just initialise the state from the props and don't do silly things like calling useState
except in response to an event or callback of some type.基本上,只需从 props 初始化状态,不要做诸如调用
useState
类的愚蠢事情,除非响应某种类型的事件或回调。
You don't.你没有。 The kind of component in your example is called "stateless functional component".
您示例中的组件类型称为“无状态功能组件”。 It has no state and no lifecycle methods.
它没有状态,也没有生命周期方法。 If you want your component to be stateful you'll have to write it as a class component.
如果您希望组件有状态,则必须将其编写为类组件。
To simulate constructor in FC use useEffect.要模拟 FC 中的构造函数,请使用 useEffect。
useEffect(() => {
... here your init code
}, []);
That's it!就是这样! EZ!
EZ! This useEffect runs only once when the component loads and never runs after, just don't forget to add square brackets at the end.
这个 useEffect 在组件加载时只运行一次,之后再也不运行,只是不要忘记在最后添加方括号。
you could set a useState as the first line inside of your functional component and add a function as "initial value":您可以将 useState 设置为功能组件内的第一行,并添加一个函数作为“初始值”:
const MyComponentName = props => {
useState(() => {
console.log('this will run the first time the component renders!');
});
return <div>my component!</div>;
};
You can use useMemo
hook (as below) to demonstrate as constructor for functional component.您可以使用
useMemo
钩子(如下)来演示作为功能组件的构造函数。 Somebody suggested to use useEffect
but it will be invoked after render.有人建议使用
useEffect
但它会在渲染后调用。
useMemo(() => {
console.log('This is useMemo')
}, []);
For those who want to run a function once before the component is mounted, here is a hook (written in TypeScript).对于那些想在安装组件之前运行一次函数的人,这里有一个钩子(用 TypeScript 编写)。
Normally useEffect
and useLayoutEffect
suffice, but they run after the component is mounted, and sometimes you want to run code before that happens (like a constructor).通常
useEffect
和useLayoutEffect
就足够了,但它们在组件安装后运行,有时您希望在此之前运行代码(如构造函数)。
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 />
}
Alternatively, you can use react-afc或者,您可以使用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}/>
)
}
})
The package has the necessary methods for working with state (including redux ), react-hooks , lifecycle methods and context package 具有使用state (包括redux )、 Z541EF72F67F6B7B8生命周期方法3452C80DACC84B8的必要方法
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.