使用react hook做一个小型完整项目(包括二级路由,动态路由,redux,tab切换,列表跳详情,登录, 守卫)

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 

项目源码:

https://github.com/baweireact/m-app-1705E/tree/master/16%E4%B9%A6%E6%9E%B6%EF%BC%88hook%E7%89%88%EF%BC%89

 

参考链接:

https://cloud.tencent.com/developer/article/1468196

https://react.docschina.org/docs/hooks-intro.html

 

重要代码:

Nav.js:

import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'

const Nav = (props) => {

  const handleNav = (index, id) => {
    props.onSetState('currentIndex', index)
    props.onSetState('currentId', id)
    axios({
      url: `/api/get_list?id=${id}`
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('contentList', res.data.data)
      }
    })
  }

  useEffect(() => {
    axios({
      url: '/api/get_nav'
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('navList', res.data.data)
      }
    })

    axios({
      url: `/api/get_list?id=0`
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('contentList', res.data.data)
      }
    })
  }, [])

  let { navList, currentIndex } = props
  let navListDom = navList.map((item, index) => (
    <span 
      key={item.id} 
      className={"m-nav-item " + (currentIndex === index ? 'active' : '')} 
      onClick={handleNav.bind(this, index, item.id)}>
      {item.title}
    </span>
  ))

  return (
    <div>
      {navListDom}
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    navList: state.navList,
    currentIndex: state.currentIndex
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onSetState(key, value) {
      dispatch({ type: 'SET_STATE', key, value })
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Nav)

BookList.js:

import React from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import axios from 'axios'

const BookList = (props) => {

  const handleDetail = (id) => {
    props.history.push('/index/home/detail/' + id)
  }

  const handleAdd = (item) => {
    if (!localStorage.getItem('username')) {
      props.history.push('/login')
    }
    axios({
      url: '/api/add_book',
      data: {
        item
      },
      method: 'post'
    }).then(res => {
      if (res.data.code === 200) {
        let { currentId } = props
        axios({
          url: `/api/get_list?id=${currentId}`
        }).then(res => {
          if (res.data.code === 200) {
            props.onSetState('contentList', res.data.data)
          }
        })
      }
    })
  }

  let { contentList } = props

  let listDom = contentList.map(item => (
    <div key={item.id}>
      {item.title}<button onClick={handleDetail.bind(this, item.id)}>详情</button>
      <button onClick={handleAdd.bind(this, item)} className={'m-add-btn ' + (item.is_in_my_book ? "" : 'active')}>收藏</button>
    </div>
  ))

  return (
    <div>
      {listDom}
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    contentList: state.contentList,
    currentId: state.currentId
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onSetState(key, value) {
      dispatch({ type: 'SET_STATE', key, value })
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(withRouter(BookList))

MyBook.js:

import React, { useState, useEffect } from 'react'
import { connect } from 'react-redux'
import axios from 'axios'

const MyBook = (props) => {
  const [selected, setSelected] = useState([])
  const [selectAll, setSelectAll] = useState(false)


  const handleSelected = (id, e) => {
    let { myBook } = props
    let selectedClone = JSON.parse(JSON.stringify(selected))
    let index = selectedClone.findIndex(item => item === id)
    if (e.target.checked) {
      selectedClone.push(id)
    } else {
      selectedClone.splice(index, 1)
    }
    setSelected(selectedClone)
    setSelectAll(selectedClone.length === myBook.length)
  }

  const handleDelete = (ids) => {
    axios({
      url: '/api/delete_book',
      data: {
        ids
      },
      method: 'post'
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('myBook', res.data.data)
      }
    })
  }

  const handleDeleteMore = () => {
    axios({
      url: '/api/delete_book',
      data: {
        ids: selected
      },
      method: 'post'
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('myBook', res.data.data)
      }
    })
  }

  const handleSelectAll = (e) => {
    let { myBook } = props
    setSelectAll(e.target.checked)
    if (e.target.checked) {
      let selected = myBook.map(item => item.id)
      setSelected(selected)
    } else {
      setSelected([])
    }
  }

  useEffect(() => {
    axios({
      url: '/api/get_my_book'
    }).then(res => {
      if (res.data.code === 200) {
        props.onSetState('myBook', res.data.data)
      }
    })
  }, [])

  useEffect(() => {
    console.log(selected)
  })


  let { myBook } = props

  let myBookDom = myBook.map(item => (
    <div key={item.id}>
      <input type="checkbox" checked={selected.findIndex(id => id === item.id) >= 0 ? true : false} onChange={handleSelected.bind(this, item.id)} />
      {item.title}
      <button onClick={handleDelete.bind(this, [item.id])}>删除</button>
    </div>
  ))

  return (
    <div>
      <input type="checkbox" checked={selectAll} onChange={handleSelectAll.bind(this)}></input>全选
        <button onClick={handleDeleteMore.bind(this)}>删除</button>
      {myBookDom}
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    myBook: state.myBook
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onSetState(key, value) {
      dispatch({ type: 'SET_STATE', key, value })
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyBook)

 

hook是2019年2月6号新增加的:

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2019-10-16 09:05  徐同保  阅读(1241)  评论(0编辑  收藏  举报