react中的无状态组件_在类和功能组件中React状态

react中的无状态组件

Before React 16.8, function components did not have state or lifecycle hooks. With 16.8+, function components can now use hooks to use state and you can implement side-effects on first render and after every update. To take a closer look at this, lets see how a function and class component use state and fire functions on initial and subsequent renders by building a bare-bones To-Do List apptwice — once as a class component and then again as a function component.

在React 16.8之前,功能组件没有状态或生命周期挂钩。 在16.8+中,功能组件现在可以使用挂钩来使用状态,并且可以在首次渲染时以及每次更新后实现副作用。 为了更深入地了解这一点,让我们通过构建一个准系统的待办事项列表应用程序来了解函数和类组件如何在初始渲染和后续渲染中使用状态和触发函数- 两次 -一次作为类组件 ,然后再次作为功能组件

配置 (Setting up)

The first noticeable difference between class and function components is, of course, their syntax. A class component extends from React.Component and sets up a render function that returns a React component.

当然,类和函数组件之间的第一个明显区别是它们的语法。 类组件是从React.Component扩展而来的,并设置了一个返回React组件的渲染函数。

import React, { Component } from 'react';class ClassComponent extends Component {
render() {
return ();
}
}export default ClassComponent;

Where as a function component is plain JavaScript that accepts props as an argument and returns a React component.

作为函数组件的是纯JavaScript,它接受props作为参数并返回React组件。

import React from 'react';const FunctionComponent = () => {
return ();
}export default FunctionComponent

初始化状态 (Initializing state)

Our state is a JavaScript object containing data that can be binded to the output of the render function. Whenever a state property is updated, React re-renders the component accordingly. In class components there are two ways to initialize state — in a constructor function or as a Class property.

我们的状态是一个JavaScript对象,其中包含可以绑定到render函数输出的数据。 每当状态属性被更新时,React都会相应地重新渲染组件。 在类组件中,有两种初始化状态的方法-在构造函数中或作为Class属性。

Constructor functions, introduced in ES6, is the first function called in a class when it is first instantiated — meaning when a new object is created from the class. Initializing the state within the constructor function allows the state object to be created before React renders the component.

ES6中引入的构造函数是在首次实例化时在类中调用的第一个函数,即从该类创建新对象时。 在构造函数中初始化状态允许在React渲染组件之前创建状态对象。

import React, { Component } from 'react';class ClassComponent extends Component {constructor(props) {
super(props);
this.state = {
list: [],
currentItem: '',
}
}

render() {
return ();
}
}export default ClassComponent;

We can also use the Class property to initialize state. Once an instance of the class is in memory, the state’s properties are created and can be read by the render function.

我们还可以使用Class属性来初始化状态。 一旦类的实例进入内存,便会创建状态的属性,并可以由render函数读取该状态的属性。

import React, { Component } from 'react';class ClassComponent extends Component {this.state = {
list: [],
currentItem: '',
}

render() {
return ();
}
}export default ClassComponent;

Both approaches net the same output so it all just comes down to preference. For the sake of this post, I’ll be sticking with the constructor function approach as we continue our comparison.

两种方法都获得相同的输出,因此只能归结为偏好。 为了这篇文章的缘故,在继续进行比较时,我将坚持使用构造函数方法。

With React 16.8, function components can now use state. Before this, data from the state had to be passed down as props from class components to function components or you had to convert your function component to a class component. Now, we can use React hooks, and to use state we can use the useState hook. You declare a state variable along with a set state variable by using array destructuring instead of declaring state as an object and setting as many properties as you need all at once.

在React 16.8中,功能组件现在可以使用状态。 在此之前,必须将状态数据作为道具从类组件传递到功能组件,或者您必须将功能组件转换为类组件。 现在,我们可以使用React钩子,要使用状态,可以使用useState钩子。 通过使用数组解构,而不是将state声明为对象,并一次设置所需的所有属性,可以声明一个状态变量以及一个set状态变量。

import React, { useState } from 'react';const FunctionComponent = () => {const [list, setList] = useState([]);
const [currentItem, setCurrentItem = useState('');

return ();
}export default FunctionComponent

渲染组件 (Render components)

Great, now that we have our state initialized, let’s render our components. I’m going to add some items to our list property in the state so we have some data to render. Note that each item in the list is an object with three properties each — an id, a task, and a completed property which indicates if a task on our to-do list has been finished. I’m also going to install and import react-flexbox-grid so we have an easy to use grid system.

太好了,既然我们已经初始化了状态,让我们渲染我们的组件。 我将某些项目添加到我们的list属性的state ,所以我们有一些数据来呈现。 请注意, list中的每个项目都是一个具有三个属性的对象-每个id ,一个task和一个completed属性,该属性指示待办事项列表上的任务是否已经完成。 我还将安装并导入react-flexbox-grid以便我们拥有易于使用的网格系统。

类组件: (Class Component:)

import React, { Component } from 'react';import { Grid, Row, Col } from 'react-flexbox-grid';class ClassComponent extends Component {
constructor(props) {
super(props);
this.state = {list: [
{
id: 1,
task: 'Create tasks',
completed: false,
},
{
id: 2,
task: 'Read tasks',
completed: false,
},
{
id: 3,
task: 'Mark complete',
completed: false,
},
{
id: 4,
task: 'Delete tasks',
completed: false,
},
],
currentItem: '',

}
}
render() {
return (<Grid fluid>
<Row>
<Col xs={6} md={3}>
<h3>Things to do:</h3>
<ul>
{this.state.list.length ? ( this.state.list.map( item => (
<React.Fragment key={item.id}>
<li>
{item.task}
</li>
</React.Fragment>
))
) : (null)
}
</ul>
</Col>
</Row>
</Grid>

);
}
}export default ClassComponent;

功能组成: (Function component:)

import React, { useState } from 'react';const FunctionComponent = () => {
const [list, setList] = useState([{
id: 1,
task: 'Create tasks',
completed: false,
},
{
id: 2,
task: 'Read tasks',
completed: false,
},
{
id: 3,
task: 'Mark complete',
completed: false,
},
{
id: 4,
task: 'Delete tasks',
completed: false,
},

],);
const [currentItem, setCurrentItem] = useState('');
return (<Grid fluid>
<Row>
<Col xs={6} md={3}>
<h3>Things to do:</h3>
<ul style={{listStyleType: 'none'}}>
{list.length ? (
list.map( item => (
<React.Fragment key={item.id}>
<li>
{item.task}
</li>
</React.Fragment>
))
) : (null)
}
</ul>
</Col>
</Row>
</Grid>

);
}export default FunctionComponent

设定状态 (Setting state)

Now that we have initialized state and rendered out our components let’s add some functionality that will manipulate our state data such as adding tasks, marking tasks complete, and deleting tasks. This will allow us to see the difference in how state is updated in class and function components.

现在我们已经初始化了状态并渲染了组件,让我们添加一些功能来操纵状态数据,例如添加任务,标记任务完成和删除任务。 这将使我们看到类和函数组件中状态更新方式的不同。

In both class and function components, when updating the state, you should not update it directly. For class components the provided method is setState. For function components, we can use the set state variable we declared when we initialized our state using the React hook useState.

在类和函数组件中,更新状态时,都不应直接更新状态。 对于类组件,提供的方法是setState 。 对于功能组件,我们可以使用在使用React钩子useState初始化状态时声明的set状态变量。

在类组件中添加任务: (Adding task in a class component:)

I’d like to add a text input field to allow a user to add a task to their to-do list. I will set the value attribute to this.state.currentItem which we just initialized in our state object and I’ll also create a handleChange function that will fire through the onChange attribute of the input tag. The handleChange function will use setState to update the currentItem property of the state. This is known as a controlled component — when an input’s value is controlled by React and not HTML. Now, as the user types in the input field, the currentItem is being updated with every keystroke.

我想添加一个文本输入字段,以允许用户将任务添加到他们的待办事项列表中。 我将value属性设置为我们刚刚在state对象中初始化的this.state.currentItem ,我还将创建一个handleChange函数,该函数将通过input标签的onChange属性触发。 该handleChange功能将使用setState更新currentItem的财产state 。 这被称为受控组件-当输入值由React而不是HTML控制时。 现在,当用户在输入字段中键入内容时,每次击键都会更新currentItem

handleChange = e => this.setState({currentItem: e.target.value})

Note that setState accepts an object which updates the state with the corresponding property or properties in that object.

请注意, setState接受一个对象,该对象使用该对象中的一个或多个相应属性更新状态。

I will also wrap the input tag with form tags and set the onSubmit attribute to a handleSubmit function. This will tack on another item in the list array. That item will be an object with the same three properties we noted earlier. After preventing the default behavior of an onSubmit, which is refreshing the page, we’ll need to generate a uniqueid and then set the state to push the new item to the list. I’ll be using setState again but this time, instead of passing in an object, I’ll pass in a function that returns an object. Because our new state depends on grabbing data from the previous state, we can pass in the previous state to do exactly that. Our handleChange function updated the currentItem so now our handleSubmit needs to grab the value of the currentItem and set that to the task property of the new item. Finally, for the third property we will set completed to false. Also, by passing in a function, we can run some code before returning our object. I’ll declare a const newItem and set it equal to an object with our three properties. Now we can return an object setting the list property to an array that spreads out the list from the previous state and adds the newItem at the end of the array. We can also set currentItem to an empty string. This will reset the input field to be blank, making it easier for the user to type in another task.

我还将用form标签包装input标签,并将onSubmit属性设置为handleSubmit函数。 这将添加到list数组中的另一个项目上。 该项目将是一个具有我们前面提到的三个属性的对象。 在防止onSubmit的默认行为(刷新页面)之后,我们需要生成一个唯一的id ,然后设置状态以将新项目推送到列表中。 我将再次使用setState ,但这一次,我将传递一个返回对象的函数,而不是传递对象。 因为我们的新状态依赖于从先前状态中获取数据,所以我们可以传递先前状态来准确地做到这一点。 我们的handleChange函数更新了currentItem因此现在我们的handleSubmit需要获取currentItem的值并将其设置为新项目的task属性。 最后,对于第三个属性,我们将completed设置为false 。 另外,通过传入一个函数,我们可以在返回对象之前运行一些代码。 我将声明一个const newItem并将其设置为具有我们三个属性的对象。 现在,我们可以返回一个将list属性设置为数组的对象,该数组将list从先前的状态分散开,并在数组的末尾添加newItem 。 我们还可以将currentItem设置为空字符串。 这会将输入字段重置为空白,从而使用户更容易键入其他任务。

import React, { Component } from 'react';
import { Grid, Row, Col } from 'react-flexbox-grid';class ClassComponent extends Component {
.
.
.handleChange = e => this.setState({currentItem: e.target.value}) handleSubmit = e => {
e.preventDefault()
// generate an unused id
let newId = 1;
let sortedListByIds = this.state.list.slice().sort((a, b) => (a.id - b.id))
for (let i = 0; i < sortedListByIds.length; i++) {
if (newId === sortedListByIds[i].id) {
newId++
}
}
this.setState(prevState => {
const newItem = {
id: newId,
task: prevState.currentItem,
completed: false,
}
return {
list: [...prevState.list, newItem],
currentItem: '',
}
})
}
render() {
return (
<Grid fluid>
<Row>
<Col xs={6} md={3}>
.
.
.
</Col><Col xs={6} md={6}>
<h4>Add task:</h4>
<form onSubmit={this.handleSubmit}>
<input type="text" autoFocus value={this.state.currentItem} onChange={this.handleChange} />
<button type="submit">+</button>
</form>
</Col>

</Row>
</Grid>
);
}
}export default ClassComponent;

在功能组件中添加任务: (Adding task in a function component:)

For the function component the form and input tags will be exactly the same as how we set them up in the class component. The handleChange and handleSubmit will use the set variables we declared when we initialized our state via the useState React hook. Recall that when we set up our array destructuring for currentItem the second item was setCurrentItem. This is what we use to update our currentItem.

对于功能组件, forminput标签将与我们在类组件中进行设置的方式完全相同。 handleChangehandleSubmit将使用通过useState React钩子初始化状态时声明的设置变量。 回想一下,当我们为currentItem设置数组结构时,第二项是setCurrentItem 。 这就是我们用来更新currentItem

const handleChange = e => setCurrentItem(e.target.value)

For the handleSubmit function we’ll still prevent the default behavior and we’ll still generate a unique id but we’ll update the state using the useState React hook. Unlike in the class component where we can update two properties at once, with useState we have to do it separately for each. To add the new item to our list, like in the class component we’ll need to access the previous list. useState can also accept a function as an argument and we can pass in an argument to that function, in our case prevList, to grab the previous data. To reset the input field we can pass in an empty string in setCurrentItem

对于handleSubmit函数,我们仍将阻止默认行为,并且仍将生成唯一的id但将使用useState React钩子更新状态。 与在类组件中我们可以一次更新两个属性不同,对于useState我们必须分别为每个属性进行更新。 要将新项添加到我们的list ,就像在类组件中,我们需要访问上一个listuseState还可以接受一个函数作为参数,我们可以将一个参数传递给该函数,在我们的例子中是prevList ,以获取先前的数据。 要重置输入字段,我们可以在setCurrentItem传递一个空字符串...

const handleSubmit = e => {
e.preventDefault() // generate an unused id
let newId = 1;
let sortedListByIds = list.slice().sort((a, b) => (a.id - b.id))
for (let i = 0; i < sortedListByIds.length; i++) {
if (newId === sortedListByIds[i].id) {
newId++
}
}setList(prevList => {
const newItem = {
id: newId,
task: currentItem,
completed: false,
}
return [...prevList, newItem]
})
setCurrentItem('')

}

切换完整状态并删除类组件中的任务: (Toggling complete status and deleting a task in a class component:)

For both the class and function component the jsx for marking an item as complete or incomplete and for the button to delete a task will be the same. Clicking a list item will give it a strike-through to indicate the task is complete and clicking it again will remove the strike-through indicating that it is not complete. Each list item will also have a button to delete the item from the list.

对于类和函数组件,用于将项目标记为完成或未完成以及用于删除任务的按钮的jsx都是相同的。 单击列表项将给它一个删除线以指示任务已完成,再次单击它将删除该删除线以指示该任务未完成。 每个列表项还将具有一个按钮,用于从列表中删除该项目。

.
.
.
<ul style={{listStyleType: 'none'}}>
{list.length ? (
list.map( item => (
<React.Fragment key={item.id}>
<li onClick={() => toggleCompleteStatus(item.id)} style={{textDecoration: item.completed ? 'line-through' : 'none'}}>
{item.task}
</li> <button onClick={() => deleteTask(item.id)}>x</button>
</React.Fragment>
))
) : (null)
}
</ul>
.
.
.

Now let’s wire these up to some functions. For toggleCompleteStatus we’ll pass in an id and use setState to return an object with a list property. We’ll use the map method to map through the current list and find the item with the matching id and toggle that item’s complete status from false to true or vice versa.

现在让我们将它们连接到某些功能。 对于toggleCompleteStatus我们将传入id并使用setState返回具有list属性的对象。 我们将使用map方法来映射当前list ,找到具有匹配id的项目,并将该项目的完整状态从false切换为true ,反之亦然。

toggleCompleteStatus = id => {
this.setState(() => {
return {
list: this.state.list.map( item => item.id === id ? {...item, completed: !item.completed} : item)
}
}
}

For the deleteTask function, we’ll also pass in an id. We’ll also declare a variable let filteredList and we’ll use the filter method to search each item in the list for an id that doesn’t match the argument. All items that don’t match will be returned in a new array leaving out the item that is being deleted. We can then use setState to return an object with the list property equal to an array with the filteredList spread out.

对于deleteTask函数,我们还将传递一个id 。 我们还将声明一个变量let filteredList并使用filter方法在list中的每个项目中搜索与参数不匹配的id 。 所有不匹配的项目都将以新数组的形式返回,而忽略了要删除的项目。 然后我们可以使用setState与返回一个对象list属性等于阵列与filteredList展开。

deleteTask = id => {
let filteredList = this.state.list.filter( item => item.id !== id)
this.setState({
list: [...filteredList]
}
}

切换完整状态并删除功能组件中的任务: (Toggling complete status and deleting a task in a function component:)

In a function component these functions will look quite similar except we’ll again be using the set state variable we declared with React’s useState to update our data instead of setState. The array methods we used — map and filter — are used the same exact way.

在函数组件中,这些函数看起来非常相似,只是我们将再次使用通过React的useState声明的set状态变量来更新数据,而不是setState 。 我们使用的数组方法( mapfilter )的使用方法相同。

const toggleCompleteStatus = id => {setList(list.map( item => item.id === id ? {...item, completed: !item.completed} : item))
}const deleteTask = id => {
let filteredList = list.filter( item => item.id !== id)setList([...filteredList])
}

生命周期和使用效果挂钩 (Lifecycle and useEffect Hooks)

Class components can use lifecycle hooks to fire functions at specific points in a components life. For instance, a good time to fetch data from an api is during the componentDidMount hook which runs after the component output has been rendered to the DOM. Function components, however, do not have lifecycle hooks but can still fire side-effects on first render and after every update. So firing a side-effect on first render only is equivalent to firing a function on the componentDidMount hook. This is done using the React hook useEffect.

类组件可以使用生命周期挂钩在组件生命中的特定点激发功能。 例如,从api获取数据的好时机是在componentDidMount挂钩期间,该挂钩在将组件输出呈现到DOM之后运行。 但是,功能组件没有生命周期挂钩,但仍可能在首次渲染时和每次更新后触发副作用。 因此,仅在第一次渲染时触发一个副作用等效于在componentDidMount钩子上触发一个函数。 这是使用React钩子useEffect

To show an example of both of these, let’s use localStorage as a way to make the data persistent. This will also make this to-do list app a truly functional application as the data will persist even if a user refreshes the page, closes their browser, or shuts down their computer.

为了显示这两个示例,让我们使用localStorage作为使数据持久化的一种方式。 这也将使此待办事项列表应用程序成为真正的功能应用程序,因为即使用户刷新页面,关闭其浏览器或关闭其计算机,数据仍将保留。

使用setState的回调函数保留列表项: (Persisting list items with setState’s callback function:)

The setState function accepts a second parameter which is a callback function. So for handleSubmit, toggleCompleteStatus, and deleteTask, we can tack on some code to save our list data local to the user’s device. The setItem method of localStorage will save data as a key-value pair in our user’s browser where the value is in a JSON format. In our case, we’ll be saving the value of our state's list property. The setItem method takes two arguments. This first is a string which is used as our key and the second is a JSON object which is used as our value. We’ll use the method JSON.stringify and pass in our list to convert it to a JSON object…

setState函数接受第二个参数,该参数是回调函数。 因此,对于handleSubmittoggleCompleteStatusdeleteTask ,我们可以添加一些代码以将list数据保存到用户设备本地。 localStoragesetItem方法会将数据作为键值对保存在我们的用户浏览器中,该值是JSON格式。 在本例中,我们将保存statelist属性的值。 setItem方法采用两个参数。 第一个是用作我们的键的字符串,第二个是用作我们的值的JSON对象。 我们将使用方法JSON.stringify并传入list以将其转换为JSON对象…

localStorage.setItem('list', JSON.stringify(this.state.list))

So now we can tack this on to the setState callback functions of handleSubmit, toggleCompleteStatus, and deleteTask.

现在,我们可以将其添加到handleSubmittoggleCompleteStatusdeleteTasksetState回调函数上。

handleSubmit = e => {
.
.
.
this.setState(prevState => {
const newItem = {
id: newId,
task: prevState.currentItem,
completed: false,
}
return {
list: [...prevState.list, newItem],
currentItem: '',
}
}, () => localStorage.setItem('list', JSON.stringify(this.state.list))
)
}toggleCompleteStatus = id => {
this.setState(() => {
return {
list: this.state.list.map( item => item.id === id ? {...item, completed: !item.completed} : item)
}
}, () => localStorage.setItem('list', JSON.stringify(this.state.list))
)
}deleteTask = id => {
let filteredList = this.state.list.filter( item => item.id !== id)
this.setState({
list: [...filteredList]
}, () => localStorage.setItem('list', JSON.stringify(this.state.list))
)
}

setState is an asynchronous function and its second parameter, the callback function, fires after the state is updated. This means that you can be confident that the data passed into the dev tools’ Local Storage will be the most current.

setState是一个异步函数,其第二个参数回调函数在状态更新后触发。 这意味着您可以放心,传递到开发工具的本地存储中的数据将是最新的。

You can view the Local Storage data by opening your dev tools and clicking the Application tab.

您可以通过打开开发工具并单击“应用程序”选项卡来查看本地存储数据。

Image for post

保留具有useEffect的列表项: (Persisting list items with useEffect:)

We’ve been using our ‘set’ functions to update our state in function components. While setState allows for a callback function as a second parameter in class components, our set state functions do not have this same convenience. However, we can use the React hook useEffect to fire side-effects whenever a particular state updates. Lets import useEffect like so…

我们一直在使用“设置”功能来更新功能组件中的状态。 尽管setState允许将回调函数作为类组件中的第二个参数使用,但是我们的set state函数没有这种便利。 但是,每当特定状态更新时,我们都可以使用React钩子useEffect触发副作用。 让我们像这样导入useEffect…

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

Instead of adding code to one of our current functions, we pass in an anonymous function as the first parameter for useEffect and an array of variables for the second parameter. The block of code in the anonymous function will fire every time one of the variables in the second parameter’s array is updated.

而不是将代码添加到当前函数中,我们将一个匿名函数作为useEffect的第一个参数useEffect并将变量数组作为第二个参数的useEffect 。 每当第二个参数数组中的变量之一更新时,匿名函数中的代码块就会触发。

useEffect(() => {
localStorage.setItem('list', JSON.stringify(list))
}, [list])

Note how the second argument has an array with the variable list in it. Since handleSubmit, toggleCompleteStatus, and deleteTask all update the list state, then this useEffect function will fire every time those functions update list.

请注意,第二个参数如何具有一个包含变量list的数组。 由于handleSubmittoggleCompleteStatusdeleteTask的所有更新的list的状态,那么这个useEffect功能将火每次这些功能的更新list

在componentDidMount上获取本地数据: (Get local data on componentDidMount:)

Cool, so now we can set data to our Local Storage in both class and function components but we still need to get the data so it can be rendered to the DOM.

很酷,所以现在我们可以在类和函数组件中都数据设置到本地存储中,但是我们仍然需要获取数据以便将其呈现到DOM。

For both our class and function component, we do have an initial state for our list items but we want to check if there is local data as well, so if a user has already used this app they can see their task list as it was when they last loaded the site.

对于我们的类和函数组件,我们确实具有list项的初始状态,但是我们也想检查是否有本地数据,因此,如果用户已经使用了此应用程序,则他们可以看到其任务列表他们上次加载该网站。

The best time to grab this data for a class component is during the componentDidMount lifecycle hook which occurs right after the class component has rendered. We’ll use the getItem method of localStorage which accepts one argument which is a string of the name of the key that stores our data — in our case 'list'. We will also have to use JSON.parse() to convert our JSON string to an array. If a user has no local data then it will return null. If it is null then we won’t need to set our state and the initial state we set in our constructor function will remain and render. If it’s not null then we’ll set our state to update the list property with the data we just grabbed.

为类组件获取此数据的最佳时间是在componentDidMount生命周期挂钩期间,该钩子在类组件呈现后立即发生。 我们将使用localStoragegetItem方法,该方法接受一个参数,该参数是存储数据的键名的字符串(在我们的情况下为'list' 。 我们还必须使用JSON.parse()将JSON字符串转换为数组。 如果用户没有本地数据,则它将返回null 。 如果为null则无需设置状态,并且在构造函数中设置的初始状态将保留并呈现。 如果它不为null则将设置state以使用刚刚获取的数据更新list属性。

componentDidMount() {
let localList = JSON.parse(localStorage.getItem('list'));
if (localList !== null) {
this.setState(() => {
return {
list: localList
}
})
}
}

使用useEffect获取初始渲染的本地数据: (Get local data on initial render with useEffect:)

We now know that we can fire side-effects whenever one of our state variables update. But if function components don’t have life-cycle hooks how can we fire side-effects on initial render? For this, all we have to do is pass in an empty array as the second parameter. In this case, useEffect will only fire on initial render just like componentDidMount.

现在我们知道,只要我们的状态变量之一更新,我们就可以触发副作用。 但是,如果功能组件没有生命周期挂钩,我们如何在初始渲染时激发副作用? 为此,我们要做的就是传递一个空数组作为第二个参数。 在这种情况下,useEffect将仅在初始渲染时触发,就像componentDidMount一样。

useEffect(() => {
let localList = JSON.parse(localStorage.getItem('list'));
if (localList !== null) {
setList(localList)
}
}, []) // empty array as second argument will behave exactly like componentDidMount

结论 (Conclusion)

And that’s it! We now have a fully functional to-do list application built two different ways — through a class component and through a function component. We have an initial state of list items that load the first time a user uses this app. They can add and delete tasks. They can mark tasks as complete or incomplete. And the data saves in their browser’s localStorage so if they close their browser and later come back to this site their data will still be available to see and update as needed. No need to save to a cloud or log into an account. The privacy of their data is as good as their device’s privacy is. This was a bare-bones implementation so I’ll leave the CSS up to you. My hope from this is that you learned or reinforced your knowledge of the difference of how state is initialized and updated through class and function components in React and how to use life-cycle hooks and useEffect. Thanks for reading and making it this far. Be good people!

就是这样! 现在,我们有一个功能齐全的待办事项清单应用程序,通过两种不同的方式构建-通过类组件和通过功能组件。 我们具有列表项的初始状态,这些列表项会在用户首次使用此应用时加载。 他们可以添加和删除任务。 他们可以将任务标记为已完成或未完成。 并且数据保存在浏览器的localStorage中,因此,如果他们关闭浏览器并稍后返回此站点,则仍可以根据需要查看和更新​​数据。 无需保存到云或登录帐户。 他们数据的隐私与他们设备的隐私一样好。 这是一个简单的实现,因此我将把CSS留给您。 我的希望是,您了解或加强了关于如何通过React中的类和函数组件初始化和更新状态以及如何使用生命周期挂钩和useEffect 。 感谢您的阅读和学习。 做个好人!

View app: https://darrylmendonez.github.io/barebones-react-todo-list/#/

查看应用程序: https : //darrylmendonez.github.io/barebones-react-todo-list/#/

View repo: https://github.com/darrylmendonez/barebones-react-todo-list

查看仓库: https : //github.com/darrylmendonez/barebones-react-todo-list

翻译自: https://medium.com/@dmendonez/react-state-in-class-and-function-components-2269614579c4

react中的无状态组件

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值