react待办事项_使用React创建一个简单的待办应用

react待办事项

You could be wondering what is so special about React; What we will do is pick up from a previous post about React components and put to practice the theories we discussed following community best practices as always.

您可能想知道React有什么特别之处? 我们要做的是从先前有关React组件的文章中摘录,并一如既往地实践我们按照社区最佳实践讨论的理论。

As the topic implies, we are going to be building a To-Do application with React. Do not expect any surprises such as managing state with a state management library like Flux or Redux. I promise it will strictly be React. Maybe in following articles we can employ something like Redux but we want to focus on React and make sure everybody is good with React itself.

正如主题所暗示的那样,我们将使用React构建一个To-Do应用程序。 不要期望会出现任何意外情况,例如使用诸如FluxRedux之类的状态管理库来管理状态。 我保证它将完全是React。 也许在接下来的文章中,我们可以使用Redux之类的东西,但是我们希望专注于React,并确保每个人都对React本身很满意。

先决条件 ( Prerequisites )

You don't need much requirements to setup this project because we will make use of CodePen for demos. You can follow the demo or setup a new CodePen pen. You just need to import React and ReactDOM library:

您不需要太多要求来设置此项目,因为我们将使用CodePen进行演示。 您可以按照演示进行操作,也可以设置新的CodePen笔。 您只需要导入React和ReactDOM库:

<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>To-Do</title>
</head>
<body>

    <div class="container">
      <div id="container" class="col-md-8 col-md-offset-2">  </div>
    </div>  

    <script src="https://fb.me/react-15.1.0.js"></script>
    <script src="https://fb.me/react-dom-15.1.0.js"></script>

</body>
</html>

ReactDOM is a standalone library that is used to render React components on the DOM.

ReactDOM是一个独立的库,用于在DOM上呈现React组件。

组件类型 ( Types of Components )

There are two types of component. These types are not just react-based but can be visualized in any other component-based UI library or framework. They include:

有两种类型的组件。 这些类型不仅基于React,而且可以在任何其他基于组件的UI库或框架中可视化。 它们包括:

  • Presentation Component

    演示组件
  • Container Component

    容器组件

Presentation Component: These are contained components that are responsible for UI. They are composed with JSX and rendered using the render method. The key rule about this type of component is that they are stateless meaning that no state of any sort is needed in such components. Data is kept in sync using props.

演示组件 :这些是负责UI的包含组件。 它们由JSX组成,并使用render方法进行渲染。 有关此类组件的关键规则是它们是无状态的,这意味着此类组件中不需要任何状态。 数据使用props保持同步。

If all that a presentation component does is render HTML based on props, then you can use stateless function to define the component rather than classes.

如果表示组件所做的只是基于props呈现HTML,则可以使用无状态函数来定义组件而不是类。

Container Component: This type of component complements presentation component by providing states. It's always the guy at the top of the family tree, making sure that data is coordinated.

容器组件 :这种类型的组件通过提供状态来补充表示组件。 始终是家谱树顶端的家伙,确保数据得到协调。

You do not necessarily need a state management tool outside of what React provides if what you are building does not have too much nested children and less complex. A To-Do is is simple so we can do with what React offers for now provided we understand how and when to use a presentation or container component

如果您要构建的内容没有太多的嵌套子代且不太复杂,那么您不一定需要在React提供的功能之外需要状态管理工具。 待办事项很简单,只要我们了解如何以及何时使用演示容器组件,就可以使用React现在提供的功能

识别演示组件 ( Recognizing Presentation Components )

It is a recommended practice to have a rough visual representation of what you are about to build. This practice is becomes very important when it comes to component-based designs because it is easier to recognize presentation components.

建议您对要构建的内容进行大致的视觉呈现。 当涉及到基于组件的设计时,这种做法变得非常重要,因为它更易于识别表示组件。

Todo Sketch

Your image must not be a clean sketch made with a sketch app. It can just be a pencil work. The most important thing is that you have a visual representation of the task at hand.

您的图片不得是使用素描应用制作的干净素描。 可以只是铅笔作品。 最重要的是,您可以直观地看到任务。

From the above diagram, we can fish out our presentation components:

从上面的图中,我们可以探究我们的演示组件:

  • TodoForm : purple

    TodoForm:紫色
  • Title: green

    标题:绿色
  • TodoList: red

    TodoList:红色
  • Todo: grey

    待办事项:灰色

待办事项表格 (Todo Form)

Functional components (a.k.a stateless components) are good for presentation components because they are simple to manage and reason about when compared with class components.

功能组件(又称无状态组件)非常适合表示组件,因为它们与类组件相比易于管理且易于推理。

For that sake, we will create the first presentation component, TodoForm, with a functional component:

为此,我们将创建第一个表示组件TodoForm ,其中包含一个功能组件:

const TodoForm = ({addTodo}) => {
  // Input tracker
  let input;

  return (
    <div>
      <input ref={node => {
        input = node;
      }} />
      <button onClick={() => {
        addTodo(input.value);
        input.value = '';
      }}>
        +
      </button>
    </div>
  );
};

Functional components just receive props (which we destructured with ES6) as arguments and return JSX to be rendered. TodoForm has just one prop which is a handler that handles the click event for adding a new todo.

功能组件仅接收props(我们使用ES6对其进行了结构分解 )作为参数,并返回要渲染的JSX。 TodoForm只有一个道具,它是一个处理click事件的处理程序,用于添加新的待办事项。

The value of the input is passed to the input member variable using React's ref.

使用React的ref将输入的值传递到input成员变量。

待办事项和待办事项清单 (Todo & Todo List)

These components present the list of to-do. TodoList is a ul element that contains a loop of Todo components (made of li elements`):

这些组件显示了待办事项列表。 TodoListul元素,包含一个Todo组件循环(由li元素组成):

const Todo = ({todo, remove}) => {
  // Each Todo
  return (<li onClick(remove(todo.id))>{todo.text}</li>);
}

const TodoList = ({todos, remove}) => {
  // Map through the todos
  const todoNode = todos.map((todo) => {
    return (<Todo todo={todo} key={todo.id} remove={remove}/>)
  });
  return (<ul>{todoNode}</ul>);
}

See the Pen AXNJpJ by Chris Nwamba (@christiannwamba) on CodePen.

CodePen上查看Chris Nwamba( @christiannwamba )的Pen AXNJpJ

The remove property is an event handler that will be called when the list item is clicked. The idea is to delete an item when it is clicked. This will be taken care of in the container component.

remove属性是一个事件处理程序,将在单击列表项时调用它。 想法是在单击项目时将其删除。 这将在容器组件中解决。

The only way the remove property can be passed to it's to the Todo component is via it's parent (not grand-parent). For this sake, in as much as the container component that will own TodoList should handle item removal, we still have to pass down the handler from grand-parent to grand-child through the parent.

可以将remove属性传递给Todo组件的唯一方法是通过其父级(而不是祖父母级)。 因此,尽管拥有TodoList的容器组件应该处理项目删除,我们仍然必须通过父级将处理程序从TodoList传递到TodoList

This is a common challenge that you will encounter in a nested component when building React applications. If the nesting is going to be deep, it is advised you use container components to split the hierarchy.

这是构建React应用程序时在嵌套组件中会遇到的常见挑战。 如果嵌套要深,建议您使用容器组件拆分层次结构。

标题 (Title)

The title component just shows the title of the application:

标题组件仅显示应用程序的标题:

const Title = () => {
  return (
    <div>
       <div>
          <h1>to-do</h1>
       </div>
    </div>
  );
}

容器组件(Todo应用) ( Container Component (Todo App) )

This will eventually become the heart of this application by regulating props and managing state among the presentation components. We already have a form and a list that are independent on each other but we need to do some tying together where needed.

通过在演示组件之间调整道具和管理状态,这最终将成为此应用程序的核心。 我们已经有一个彼此独立的表单和列表,但是我们需要在需要时进行一些绑定。

// Contaner Component
// Todo Id
window.id = 0;
class TodoApp extends React.Component{
  constructor(props){
    // Pass props to parent class
    super(props);
    // Set initial state
    this.state = {
      data: []
    }
  }
  // Add todo handler
  addTodo(val){
    // Assemble data
    const todo = {text: val, id: window.id++}
    // Update data
    this.state.data.push(todo);
    // Update state
    this.setState({data: this.state.data});
  }
  // Handle remove
  handleRemove(id){
    // Filter all todos except the one to be removed
    const remainder = this.state.data.filter((todo) => {
      if(todo.id !== id) return todo;
    });
    // Update state with filter
    this.setState({data: remainder});
  }

  render(){
    // Render JSX
    return (
      <div>
        <Title />
        <TodoForm addTodo={this.addTodo.bind(this)}/>
        <TodoList 
          todos={this.state.data} 
          remove={this.handleRemove.bind(this)}
        />
      </div>
    );
  }
}

View CodePen Progress

查看CodePen进度

We first setup the component's constructor by passing props to the parent class and setting the initial state of our application.

我们首先通过将prop传递给父类并设置应用程序的初始状态来设置组件的构造函数。

Next we create handlers for adding and removing todo which the events are fired in TodoForm component and Todo component respectively. setState method is used to update the application state at any point.

接下来,我们创建用于添加和删除待办事项的处理程序,这些事件分别在TodoForm组件和Todo组件中触发。 setState方法用于随时更新应用程序状态。

As usual, we render the JSX passing in our props which will be received by the the child components.

像往常一样,我们渲染JSX传递我们的道具,这些道具将被子组件接收。

DOM渲染 ( DOM Rendering )

We have been rendering our demo components to the browser without discussing how but can be seen in the CodePen samples. React abstracts rendering to a different library called ReactDOM which takes your app's root component and renders it on a provided DOM using an exposed render method:

我们一直在将演示组件呈现给浏览器,而没有讨论如何在CodePen示例中看到。 React将渲染抽象到另一个名为ReactDOM的库中,该库获取应用程序的根组件,并使用公开的render方法在提供的DOM上渲染它:

ReactDOM.render(<TodoApp />, document.getElementById('container'));

The first argument is the component to be rendered and the second argument is the DOM element to render on.

第一个参数是要渲染的组件,第二个参数是要在其上渲染的DOM元素。

使用服务器 ( Working with a Server )

We could step up our game by working with a HTTP server rather than just a simple local array. We do not have to bear the weight of jQuery to make HTTP request, rather we can make use of a smaller library like Axios.

我们可以通过使用HTTP服务器而不是简单的本地数组来增强我们的游戏。 我们不必承担jQuery发出HTTP请求的重担,而是可以使用较小的库(例如Axios)

<script src="https://npmcdn.com/axios/dist/axios.min.js"></script>

React lifecycle methods help you hook into React process and perform some actions. An example is doing something once a component is ready. This is done in the componentDidMount lifecycle method. Lifecycle methods are just like normal class methods and cannot be used in a stateless component.

React生命周期方法可帮助您加入React流程并执行一些操作。 一个示例是在组件准备就绪后立即执行操作。 这是在componentDidMount生命周期方法中完成的。 生命周期方法就像普通的类方法一样,不能在无状态组件中使用。

class TodoApp extends React.Component{
  constructor(props){
    // Pass props to parent class
    super(props);
    // Set initial state
    this.state = {
      data: []
    }
    this.apiUrl = 'https://57b1924b46b57d1100a3c3f8.mockapi.io/api/todos'
  }
  // Lifecycle method
  componentDidMount(){
    // Make HTTP reques with Axios
    axios.get(this.apiUrl)
      .then((res) => {
        // Set state with result
        this.setState({data:res.data});
      });
  }
}

Mock API is a good mock backend for building frontend apps that needs to consume an API in the future. We store the API URL provided by Mock API as a class property so it can be accessed by different members of the class just as the componentDidMount lifecycle method is. Once there is a response and the promise resolves, we update the state using:

Mock API是一个很好的模拟后端,用于构建将来需要使用API​​的前端应用程序。 我们将Mock API提供的API URL存储为类属性,以便类的不同成员可以访问它,就像componentDidMount生命周期方法一样。 收到回应并兑现承诺后,我们将使用以下方式更新状态:

this.setState()

The add and remove methods now works with the API but also optimized for better user experience. We do not have to reload data when there is new todo, we just push to the existing array. Same with remove:

现在,添加和删除方法可与API一起使用,但也进行了优化,以提供更好的用户体验。 当有新的待办事项时,我们不必重新加载数据,我们只需推送到现有阵列即可。 与删除相同:

// Add todo handler
  addTodo(val){
    // Assemble data
    const todo = {text: val}
    // Update data
    axios.post(this.apiUrl, todo)
       .then((res) => {
          this.state.data.push(res.data);
          this.setState({data: this.state.data});
       });
  }
  // Handle remove
  handleRemove(id){
    // Filter all todos except the one to be removed
    const remainder = this.state.data.filter((todo) => {
      if(todo.id !== id) return todo;
    });
    // Update state with filter
    axios.delete(this.apiUrl+'/'+id)
      .then((res) => {
        this.setState({data: remainder});      
      })
  }

数量和样式 ( Count and Style )

We could keep track of the total items in our To-Do with the Title component. This one is easy, place a property on the Title component to store the count and pass down the computed count from TodoApp:

我们可以使用“标题”组件跟踪待办事项中的全部项目。 这很简单,在Title组件上放置一个属性以存储计数,并从TodoApp传递计算的计数:

// Title
const Title = ({todoCount}) => {
  return (
    <div>
       <div>
          <h1>to-do ({todoCount})</h1>
       </div>
    </div>
  );
}
// Todo App
class TodoApp extends React.Component{
 //...
 render(){
    // Render JSX
    return (
      <div>
        <Title todoCount={this.state.data.length}/>
        <!--...-->
      </div>
    );
  }
  //...
 }

The app works as expected but not pretty enough for consumption. Bootstrap can take care of that. The following CodePen demo shows some updates made to change the look of the app:

该应用程序可正常运行,但不足以用于消费。 Bootstrap可以解决这个问题。 以下CodePen演示显示了一些更改以更改应用程序的外观:

See the Pen PzVyRm by Chris Nwamba (@christiannwamba) on CodePen.

CodePen上查看Chris Nwamba( @christiannwamba )的Pen PzVyRm

接下来是什么 ( What Next )

We violated minor best practices for brevity but most importantly, you get the idea of how to build a React app following community recommended patterns.

为了简洁起见,我们违反了一些次要的最佳做法,但最重要的是,您了解了如何按照社区推荐的模式构建React应用。

As I mentioned earlier, you don't need to use a state management library in React applications if your application is simpler. Anytime you have doubt if you need them or not, then you don't need them. (YAGNI).

如前所述,如果您的应用程序更简单,则无需在React应用程序中使用状态管理库。 每当您有疑问是否需要它们时,都不需要它们。 ( YAGNI )。

On the other hand, expect an article on Redux from Scotch soon.

另一方面,很快就会有来自Scotch的关于Redux的文章。

翻译自: https://scotch.io/tutorials/create-a-simple-to-do-app-with-react

react待办事项

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值