乐趣区

使用-React-Context-Hooks-Immer-Golang-创建一个TodoList

背景

上周末在家没啥事,想写点东西,一时不知道写什么好。然后就想起来一个去了Airbnb 的同学,说 Airbnb 的面试风格是以实操为主,她面了 8 轮,轮轮都是写代码(2018 年),令人十分害怕。

代码题目都不是很难,简单分享几道题:

然后我就看到了实现一个Todo List

这种题目不难,但是 灵活度很高 ,没有什么 限制 条件,你随意发挥,可以从多方面考察候选人。

就拿这道题下手吧,开造。

[文末有本文全部的源代码, 通过这个例子,你会了解 React ContextHooks 的使用方式,以及 如何使用 Golang 编写 CURD Api]

废话不多说了,进入正题。

功能实现

首先就是新建一个项目,不限工具,CRA 什么的都可以, 我就用了之前自己写的一个工具,简单起了项目, 不过这些都无所谓了,直接上代码:

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App.js';

ReactDOM.render(<App />, document.getElementById('root'));

App

// App.js

import React from "react";
import {TodosProvider} from './Store'
import {TodoList} from './TodoList'

const App = () => {
  return (
    <TodosProvider>
      <TodoList />
    </TodosProvider>
  );
}

export default App

Store

这里我创建了两个 Context,一个用于 存储 数据,另一个用于 更新 数据。

例如:

const initialState = []

const StateContext = React.createContext(initialState)
const UpdateContext = React.createContext(null)

被 Context 包裹的组件可以取用这些传入的值。

完整代码:

// Store.js
import React from 'react'
import produce from 'immer'

// An array of todos, where a todo looks like this: 
// {id: string; title: string; isCompleted: boolean}
const initialTodos = [{
  id: 1,
  title: "One",
  isCompleted: false
}, {
  id: 2,
  title: "Two",
  isCompleted: false
}, {
  id: 3,
  title: "Three",
  isCompleted: false
}]

const StateContext = React.createContext(initialTodos)
const UpdateContext = React.createContext(null)

export function TodosProvider({children}) {const [todos, updateTodos] = React.useReducer(produce, initialTodos)
  return (<UpdateContext.Provider value={updateTodos}>
      <StateContext.Provider value={todos}>
        {children}
      </StateContext.Provider>
    </UpdateContext.Provider>
  )
}

export function useTodos() {return [React.useContext(StateContext), React.useContext(UpdateContext)]
}

Todo 主体

这里的实现也很简单,我先简单做了两个小功能,一个是 完成 某一项,一个是 删除 某一项,完整代码:

// TodoList
import React from 'react';
import {useTodos} from './Store'

export function TodoList() {const [todos, updateTodos] = useTodos()

  const deleteTodo = id => updateTodos(todos => {const todoIdxToDelete = todos.findIndex(todo => todo.id === id)
    todos.splice(todoIdxToDelete, 1)
  })

  const completeTodo = id => updateTodos(todos => {todos.find(todo => todo.id === id).isCompleted = true
  })

  return (
    <ul>
      {todos.map(todo => (<li key={todo.id} style={todo.isCompleted ? { color: 'red'} : {color: 'green'}}>
          <span>{todo.title}</span>
          <button onClick={() => deleteTodo(todo.id)}>Delete</button>
          <button onClick={() => completeTodo(todo.id)}>Complete</button>
        </li>
      ))}
    </ul>
  )
}

DEMO:

下面把新增也一起做了。

想着都已经做到这一步了,数据一刷新就没了,干脆存到数据库里吧,最终的样子:

后端接口实现:

看下这几个 CURD 接口是怎么写的:

Api: C


Api: U

Api: R

Api: D

代码都比较简单,一眼就能看明白是做什么的,就不多做解释了。

后端完整的代码在这里:

https://github.com/beMySun/go…

前端部分完整的代码在这里:
https://github.com/beMySun/re…

数据库用的 mySql, 建库,加改表可以用这个 Sequel Pro,很方便

如果不想用这个,也可以用命令行工具来操作。

再贴几个会用的命令吧:

show databases;

use database;

describe todos_tab;

select * from todos_tab limit 10;

加一个字段:text

加一个字段:isCompleted

最后

功能很简单,但是做的时候需要考虑的东西还是很多的。

如果有朋友也想学习下,可以把代码下载下来自己运行跑一下。

后端完整的代码在这里:
https://github.com/beMySun/go…

前端部分完整的代码在这里:
https://github.com/beMySun/re…

这个后端的 demo 包含了完整的 CURD,是一个很好的学习 demo, 希望对大家的学习有所帮助。

才疏学浅,行文难免有纰漏。

若有错误,欢迎指正,谢谢。

以上。

如果本文对你有帮助,别忘了点赞呦~

参考资料:
https://learnku.com/golang/t/…
https://gorm.io/docs/update.h…

退出移动版