保安日记:React框架学习第五篇之redux

redux

一个独立专门用于做状态管理的JS库

作用: 集中式管理react应用中多个组件共享的状态

基础概念参考阮一峰的文档

传送门:

教程一:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html

教程二:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html

教程三:http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_three_react-redux.html

评论管理demo

components 文件夹里放UI组件

containers 文件夹里放容器组件

redux的文件单独放一个文件夹

index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './containers/app/app'
import {Provider} from 'react-redux'
import store from './redux/store'

ReactDOM.render(
    <Provider store = {store}>
        <App />
    </Provider>
    
, document.getElementById('root'))
/redux/action-types.js
// 包含所有action type的常量字符
export const ADD_COMMENT = 'add_comment'
export const DELETE_COMMENT = 'delete_comment'
export const RECEIVE_COMMENTS = 'receive_comments'
/redux/actions.js
//包含了所有的action creator----(action的工厂函数)
import {ADD_COMMENT,DELETE_COMMENT,RECEIVE_COMMENTS} from './action-types'

export const addComment = (comment) => ({type: ADD_COMMENT, data: comment})

export const deleteComment = (index) => ({type: DELETE_COMMENT, data: index})

export const receiveComments = (comments) => ({type: RECEIVE_COMMENTS, data: comments})

// 异步从后台获取数据
export const getComments = () => {
    return dispatch => {
        //模拟发送ajax请求异步获取数据
        setTimeout(() => {            
            const comments = [
                {username: 'Tom', content: 'React挺好的!'},
                {username: 'Jack', content: 'React好难!'},
            ]
            // 分发一个同步的action
            dispatch(receiveComments(comments))
        },1000)
    }
}
/redux/reducers.js
// 包含n个reducer函数的模块
import {ADD_COMMENT,DELETE_COMMENT,RECEIVE_COMMENTS} from './action-types'

const initComments = []
export function comments(state = initComments, action) {
    switch (action.type) {
        case ADD_COMMENT :
            return [action.data, ...state]  //在老状态state里新添加一个comment
        case DELETE_COMMENT :
//filter() 方法创建一个新的数组,不会改变原始数组。新数组中的元素是通过检查指定数组中符合条件的所有元素
            return state.filter((comment, index) => index!== action.data) //回调函数返回一个布尔值,决定comment是否加到state里面   
        case RECEIVE_COMMENTS :
            return action.data
        default : 
            return state

    }
} 
/redux/store.js
import {createStore,applyMiddleware} from 'redux'
import {comments} from './reducers'
import thunk from 'redux-thunk'
import { composeWithDevTools} from 'redux-devtools-extension'

// 生成store对象 括号里为reducer函数
export default  createStore(
    comments,  //内部会第一次调用reducer函数  得到初始state
    composeWithDevTools( applyMiddleware(thunk)) //应用上异步中间件
)
/containers/app.js
import React from 'react'
import CommentAdd from '../../components/comment-add/comment-add'
import CommentList from '../../components/comment-list/comment-list'
import {connect} from 'react-redux'
import {addComment,deleteComment,getComments} from '../../redux/actions'

class App extends React.Component {

  componentDidMount () {
    //异步获取
    this.props.getComments()
  }

  render () {
    console.log(this.props);
    const {comments,addComment,deleteComment} = this.props

    return (
      <div>
        <header className="site-header jumbotron">
          <div className="container">
            <div className="row">
              <div className="col-xs-12">
                <h1>请发表对React的评论</h1>
              </div>
            </div>
          </div>
        </header>
        <div className="container">
          <CommentAdd add={addComment}/>
          <CommentList comments={comments} delete={deleteComment}/>
        </div>
      </div>
    )
  }
}

export default connect(
  state => ({comments: state}),  //state 就是一个comments数组
  {addComment,deleteComment,getComments}
)(App)
/component/comment-add
import React from 'react'
import PropTypes from 'prop-types'

class CommentAdd extends React.Component {
  constructor (props) {
    super(props)
    this.state = {
      username: '',
      content: ''
    }
    this.addComment = this.addComment.bind(this)
    this.changeUsername = this.changeUsername.bind(this)
    this.changeContent = this.changeContent.bind(this)
  }

  addComment () {
    // 根据输入的数据创建评论对象
    let { username, content } = this.state
    let comment = { username, content }
    // 添加到comments中, 更新state
    this.props.add(comment)
    // 清除输入的数据
    this.setState({
      username: '',
      content: ''
    })
  }

  changeUsername (event) {
    this.setState({
      username: event.target.value
    })
  }

  changeContent (event) {
    this.setState({
      content: event.target.value
    })
  }

  render () {
    return (
      <div className="col-md-4">
        <form className="form-horizontal">
          <div className="form-group">
            <label>用户名</label>
            <input type="text" className="form-control" placeholder="用户名"
                   value={this.state.username} onChange={this.changeUsername}/>
          </div>
          <div className="form-group">
            <label>评论内容</label>
            <textarea className="form-control" rows="6" placeholder="评论内容"
                      value={this.state.content} onChange={this.changeContent}></textarea>
          </div>
          <div className="form-group">
            <div className="col-sm-offset-2 col-sm-10">
              <button type="button" className="btn btn-default pull-right" onClick={this.addComment}>提交</button>
            </div>
          </div>
        </form>
      </div>
    )
  }
}

CommentAdd.propTypes = {
  add: PropTypes.func.isRequired
}

export default CommentAdd
/component/comment-item
import React from 'react'
import PropTypes from 'prop-types'
import './commentItem.css'

class CommentItem extends React.Component {
  constructor (props) {
    super(props)
    this.deleteComment = this.deleteComment.bind(this)
  }

  deleteComment () {
    let username = this.props.comment.username
    if (window.confirm(`确定删除${username}的评论吗?`)) {
      this.props.delete(this.props.index)
    }
  }

  render () {
    let comment = this.props.comment
    return (
      <li className="list-group-item">
        <div className="handle">
          <a href="javascript:" onClick={this.deleteComment}>删除</a>
        </div>
        <p className="user"><span >{comment.username}</span><span>:</span></p>
        <p className="centence">{comment.content}</p>
      </li>
    )
  }
}
CommentItem.propTypes = {
  comment: PropTypes.object.isRequired,
  index: PropTypes.number.isRequired,
  delete: PropTypes.func.isRequired
}

export default CommentItem

/component/comment-list
import React from 'react'
import PropTypes from 'prop-types'
import CommentItem from '../comment-item/comment-item'
import './commentList.css'


class CommentList extends React.Component {
  constructor (props) {
    super(props)
  }

  render () {
    let comments = this.props.comments
    let display = comments.length > 0 ? 'none' : 'block'
    return (
      <div className="col-md-8">
        <h3 className="reply">评论回复:</h3>
        <h2 style={{ display: display }}>暂无评论,点击左侧添加评论!!!</h2>
        <ul className="list-group">
          {
            comments.map((comment, index) => {
              console.log(comment)
              return <CommentItem comment={comment} key={index} index={index} delete={this.props.delete}/>
            })
          }
        </ul>
      </div>
    )
  }
}
CommentList.propTypes = {
  comments: PropTypes.array.isRequired,
  delete: PropTypes.func.isRequired
}

export default CommentList
/component/commentItem.css
li {
  transition: .5s;
  overflow: hidden;
}

.handle {
  width: 40px;
  border: 1px solid #ccc;
  background: #fff;
  position: absolute;
  right: 10px;
  top: 1px;
  text-align: center;
}

.handle a {
  display: block;
  text-decoration: none;
}

.list-group-item .centence {
  padding: 0px 50px;
}

.user {
  font-size: 22px;
}
/component/commentList.css
.reply {
  margin-top: 0px;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值