作者可能是本意想要做一个图书管理系统,不过添加书籍的时候报错,所以简单的页面我们简单的看看

先上github地址:https://github.com/hesisi/react-bookManager

看package.json文件是有用到中间件的,心里多了点期待,也许帮它修复好bug也行呢

先看页面



很简单,可能只是框架的效果吧

看看代码

//src\index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
// 引入中间件
import {Provider} from 'react-redux';
// reducer
import bookReducer from './reducers/bookReducer';
// userreducer
import userReducer from './reducers/userReducer';
import { createStore ,applyMiddleware ,combineReducers } from 'redux';
import thunk from 'redux-thunk'; const rootReducer = combineReducers({
bookReducer,
userReducer
});
//store
const store = createStore(rootReducer,applyMiddleware(thunk)); ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
); store.subscribe(() => {
console.log("================监听store变化:"+JSON.stringify(store));
}); registerServiceWorker();
//app.js中定义了几个去不同页面的路由
import React from 'react';
import ReactDOM from 'react-dom';
import HomeLayout from './layouts/HomeLayout'; import BookAdd from './components/BookAdd';
import BookListContainer from './containers/BookList';
import UserAdd from './components/UserAdd';
import UserListContainer from './components/UserList';
import FileAdd from './components/FileAdd';
import FileList from './components/FileList';
import { BrowserRouter as Router ,Route } from 'react-router-dom';
import registerServiceWorker from './registerServiceWorker'; {/*
store的数据结构 store = {
bookReducer : {
data : [{},{}]
}, userReducer : {
data : [{},{}]
}
} */} class App extends React.Component{
render (){
return (
<Router>
<HomeLayout>
<div>
<Route path="/book/add" component={BookAdd}></Route>
<Route path="/book/list" component={BookListContainer}></Route>
<Route path="/user/add" component={UserAdd} ></Route>
<Route path="/user/list" component={UserListContainer}></Route>
<Route path="/file/add" component={FileAdd}></Route>
<Route path="/file/list" component={FileList}></Route>
</div>
</HomeLayout>
</Router>
); }
} export default App;

接下来我们根据路由看一下页面

//user/list
//应该是数据部分请求没有接口,所以没有数据渲染出来
import React from 'react';
import { Table ,Button ,Popconfirm ,Divider ,Modal} from 'antd';
import {initUserAction} from "../actions/userActions";
import PropTypes from 'prop-types';
import FormLayout from './Form';
import SearchInput from '../components/SearchInput'; class UserList extends React.Component{
constructor(props){
super(props); this.state = {
title : "",
visible : false,
confirmLoading : false,
formData : {},
operation : ""
};
} componentWillMount(){
const {store} = this.context;
fetch("http://localhost:3001/user")
.then(res => res.json())
.then(res => {
store.dispatch(initUserAction(res));
});
} //点击编辑
editHandle(record){
//record:{"id":10002,"name":"PHP从入门到死亡","price":89,"owner_id":10002}
this.setState({
title : "修改",
visible : true,
formData : record,
operation : "edit" //编辑状态
}); } //在子组件中点击添加需要调用的props函数
addHandle(){
this.setState({
title : "添加",
visible : true,
operation : "add"
});
} //Form表单点击确定的时候要执行的props函数,动态获取Input组件的值
comfirmHandle(data){
this.setState({
visible : false,
formData : data
}) let { operation } = this.state;
const { formData } = this.state; if(operation === "edit"){
this.props.editBook(formData);
}else{
this.props.addBook(formData);
} } //取消
cancelHandle(){
this.setState({
visible : false,
formData : {} //点击取消置空record对象
});
} render(){
const { userList, deleteUser } = this.props; //connect传递的props
const { title,visible ,confirmLoading } = this.state;
console.log("===================userlist props:"+JSON.stringify(this.props)); const columns = [{
title : '用户编号',
dataIndex : 'id'
},{
title : '名称',
dataIndex : 'name'
},{
title:'学号',
dataIndex:'student_id'
},{
title:'性别',
dataIndex:'gender'
},{
title:'操作',
render : (text,record) => (
<span type="ghost">
<Button size="small" onClick={() => this.editHandle(record)}>编辑</Button>
<Divider type="vertical" />
<Popconfirm title="确定要删除吗?" onConfirm={() => deleteUser(record)}>
<Button size="small" >删除</Button>
</Popconfirm>
</span>
)
}]; return (
<div>
<div>
<SearchInput addHandle={this.addHandle.bind(this)}/>
</div>
<Table columns={columns} dataSource={userList}/>
<Modal
title={title}
visible= {visible}
confirmLoading = {confirmLoading}
onCancel = {() => this.cancelHandle()}
footer = {null}
>
<FormLayout record={this.state.formData} comfirmHandle={this.comfirmHandle.bind(this)}/>
</Modal>
</div>
);
}
} UserList.contextTypes = {
store: PropTypes.object.isRequired
}; export default UserList;
//src\actions\userActions.js
const INIT_USER_ACTION = "INIT_USER_ACTION";
const ADD_USER_ACTION = "ADD_USER_ACTION";
const DELETE_USER_ACTION = "DELETE_USER_ACTION";
const UPDATE_USER_ACTION = "UPDATE_USER_ACTION"; export const initUserAction = (data) => {
return {
type : INIT_USER_ACTION,
payload : data
}
} export const addUserAction = (data) => {
return {
type : ADD_USER_ACTION,
payload : data
}
} export const deleteUserAction = (id) => {
return {
type : DELETE_USER_ACTION,
payload : id
}
} export const updateUserAction = (data) => {
return {
type : UPDATE_USER_ACTION,
payload : data
}
}
//src\components\SearchInput.js
import React from 'react';
import { Input ,Row ,Col ,Button } from 'antd'; const Search = Input.Search;
class SearchInput extends React.Component{
render(){
return (
//利用栅格系统,使searchInput和button在同一行
<div>
<Row>
<Col span={10}>
<Search
placeholder="输入编号查询..."
onSearch = {value => console.log(value)}
style={{ width:400 ,marginBottom :20}}
enterButton = "搜索"
/>
</Col>
<Col span={3}>
<Button type="primary" onClick={this.props.addHandle}>添加</Button>
</Col>
</Row> </div>
);
}
} export default SearchInput;
//src\components\Form.js
import React from 'react';
import { Form , Input , Button } from 'antd'; const FormItem = Form.Item;
const formItemLayout = {
labelCol : {span : 5},
wrapperCol : {span : 15}
};
class FormLayout extends React.Component{ handleSubmit(e){
e.preventDefault();
const comfirmHandle = this.props.comfirmHandle;
const fieldsValue = this.props.form.getFieldsValue(); //表单校验
this.props.form.validateFields(function(errors,value){
//校验通过
if(!errors){
comfirmHandle(fieldsValue); //获取当前表单数据并当做回调函数的参数传递给父组件
}
}); } render(){
const { getFieldDecorator ,getFeildsValue } = this.props.form;
const { record } = this.props; return (
<Form onSubmit= {this.handleSubmit.bind(this)}>
<FormItem label="编号" {...formItemLayout} style={{display:'none'}}>
{getFieldDecorator('id', {
initialValue : record ? record.id : ""
})(
<Input />
)}
</FormItem>
<FormItem label="名称" {...formItemLayout}>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入书籍名称!'
}],
initialValue : record ? record.name : ""
})(
<Input placeholder="请输入书籍名称"/>
)}
</FormItem>
<FormItem label="价格" {...formItemLayout}>
{getFieldDecorator('price', {
rules: [{
required: true, message: '请输入价格!'
},{
pattern : /(^[1-9](\d+)?(\.\d{1,2})?$)|(^(0){1}$)|(^\d\.\d{1,2}?$)/,message:'请输入正确的金额'
}],
initialValue : record ? record.price : ""
})(
<Input placeholder="请输入价格" />
)}
</FormItem>
<FormItem label="借阅者编号" {...formItemLayout}>
{getFieldDecorator('owner_id', {
rules: [{
required: true, message: '请输入借阅者编号!'
},{
pattern : /^(\d{5})$/,message:'请输入5位数字'
}],
initialValue : record ? record.owner_id :""
})(
<Input placeholder="请输入借阅者编号"/>
)}
</FormItem>
<FormItem wrapperCol={{ span: 10, offset: 10 }}>
<Button type="primary" htmlType="submit">
确定
</Button>
</FormItem>
</Form>
);
}
} export default FormLayout = Form.create()(FormLayout);

//src\components\UserAdd.js
import React from 'react'; class UserAdd extends React.Component{
render(){
return (
<div>添加用户</div>
);
}
} export default UserAdd;

//src\components\BookList.js
import React from 'react';
import { Table, Button, Popconfirm, Divider, Modal, message} from 'antd';
import {initBookAction} from "../actions/bookActions";
import PropTypes from 'prop-types';
import FormLayout from './Form';
import SearchInput from '../components/SearchInput'; class BookList extends React.Component{
constructor(props){
super(props); this.state = {
title : "",
visible : false,
confirmLoading : false,
formData : {},
operation : ""
};
} componentWillMount(){
const {store} = this.context;
fetch("http://localhost:3001/book")
.then(res => res.json())
.then(res => {
store.dispatch(initBookAction(res));
});
} //点击编辑
editHandle(record){
//record:{"id":10002,"name":"PHP从入门到死亡","price":89,"owner_id":10002}
this.setState({
title : "修改",
visible : true,
formData : record,
operation : "edit" //编辑状态
});
} //在子组件中点击添加需要调用的props函数
addHandle(){
this.setState({
title : "添加",
visible : true,
operation : "add"
});
} //Form表单点击确定的时候要执行的props函数,动态获取Input组件的值
comfirmHandle(data){ //这个地方要注意setState是异步的,
//只有在重新render的时候state的值才会被重新修改
//所以通过回调函数解决 this.setState({
visible : false,
formData : data
},() => {
let { operation } = this.state;
const { formData } = this.state; if(operation === "edit"){
this.props.editBook(formData);
}else{
this.props.addBook(formData);
//this.props.history.push("/book/list");
} //处理完之后再次置空
this.setState({
formData : {}
}) })
} //取消
cancelHandle(){
this.setState({
visible : false,
formData : {} //点击取消置空record对象
});
} render(){
const { bookList, deleteBook } = this.props; //connect传递的props
const { title,visible ,confirmLoading } = this.state; const columns = [{
title : '图书编号',
dataIndex : 'id',
key : 'id'
},{
title : '名称',
dataIndex : 'name',
key : 'name'
},{
title:'价格',
dataIndex:'price',
key : 'price'
},{
title:'借阅人编号',
dataIndex:'owner_id',
key : 'owner_id'
},{
title:'操作',
key : 'operation',
render : (text,record) => (
<span type="ghost">
<Button size="small" onClick={() => this.editHandle(record)}>编辑</Button>
<Divider type="vertical" />
<Popconfirm title="确定要删除吗?" onConfirm={() => deleteBook(record.id)}>
<Button size="small" >删除</Button>
</Popconfirm>
</span>
)
}]; return (
<div>
<div>
<SearchInput addHandle={this.addHandle.bind(this)}/>
</div>
<Table columns={columns} dataSource={bookList} rowKey="id"/>
<Modal
title={title}
visible= {visible}
confirmLoading = {confirmLoading}
onCancel = {this.cancelHandle.bind(this)}
footer = {null}
destroyOnClose
>
<FormLayout record={this.state.formData} comfirmHandle={this.comfirmHandle.bind(this)}/>
</Modal>
</div>
);
}
} BookList.contextTypes = {
store: PropTypes.object.isRequired,
router:PropTypes.object.isRequired
}; export default BookList;

import React from 'react';
import Form from './Form';
class BookAdd extends React.Component{
render(){
return (
<div>
<Form/>
</div>
);
}
} export default BookAdd;
//src\components\Form.js
import React from 'react';
import { Form , Input , Button } from 'antd'; const FormItem = Form.Item;
const formItemLayout = {
labelCol : {span : 5},
wrapperCol : {span : 15}
};
class FormLayout extends React.Component{ handleSubmit(e){
e.preventDefault();
const comfirmHandle = this.props.comfirmHandle;
const fieldsValue = this.props.form.getFieldsValue(); //表单校验
this.props.form.validateFields(function(errors,value){
//校验通过
if(!errors){
comfirmHandle(fieldsValue); //获取当前表单数据并当做回调函数的参数传递给父组件
}
}); } render(){
const { getFieldDecorator ,getFeildsValue } = this.props.form;
const { record } = this.props; return (
<Form onSubmit= {this.handleSubmit.bind(this)}>
<FormItem label="编号" {...formItemLayout} style={{display:'none'}}>
{getFieldDecorator('id', {
initialValue : record ? record.id : ""
})(
<Input />
)}
</FormItem>
<FormItem label="名称" {...formItemLayout}>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请输入书籍名称!'
}],
initialValue : record ? record.name : ""
})(
<Input placeholder="请输入书籍名称"/>
)}
</FormItem>
<FormItem label="价格" {...formItemLayout}>
{getFieldDecorator('price', {
rules: [{
required: true, message: '请输入价格!'
},{
pattern : /(^[1-9](\d+)?(\.\d{1,2})?$)|(^(0){1}$)|(^\d\.\d{1,2}?$)/,message:'请输入正确的金额'
}],
initialValue : record ? record.price : ""
})(
<Input placeholder="请输入价格" />
)}
</FormItem>
<FormItem label="借阅者编号" {...formItemLayout}>
{getFieldDecorator('owner_id', {
rules: [{
required: true, message: '请输入借阅者编号!'
},{
pattern : /^(\d{5})$/,message:'请输入5位数字'
}],
initialValue : record ? record.owner_id :""
})(
<Input placeholder="请输入借阅者编号"/>
)}
</FormItem>
<FormItem wrapperCol={{ span: 10, offset: 10 }}>
<Button type="primary" htmlType="submit">
确定
</Button>
</FormItem>
</Form>
);
}
} export default FormLayout = Form.create()(FormLayout);
//src\containers\BookList.js
import { connect } from 'react-redux';
import BookList from '../components/BookList';
import { deleteBookAction , addBookAction ,updateBookAction } from '../actions/bookActions';
import { message } from 'antd'; const mapStateToProps = (state) => {
return {
bookList : state.bookReducer.data
};
} const mapDispatchToProps = (dispatch) => {
return {
deleteBook : (id) => {
//dispatch(deleteBookAction(id))
dispatch(dispatch => {
fetch('http://localhost:3001/book/'+id,{
method : 'delete'
})
.then(res => res.json())
.then(res => {
console.log("==============删除返回参数:"+JSON.stringify(res));
dispatch(deleteBookAction(id));
message.success("删除记录成功");
})
.catch(err => {
message.error("删除记录失败");
})
})
},
addBook : (data) => {
//dispatch(addBookAction(data)) dispatch(dispatch => {
fetch('http://localhost:3001/book',{
method : 'post',
body : JSON.stringify({
name : data.name,
price : data.price,
owner_id : data.owner_id
}),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => res.json)
.then(res => {
console.log("==============添加返回参数:"+JSON.stringify(res));
dispatch(addBookAction(data))
//message.success("添加记录成功");
window.location.reload();
})
.catch(error => {
message.error("添加记录失败")
})
})
},
editBook : (data) => {
//dispatch(updateBookAction(data))
dispatch(dispatch => {
fetch('http://localhost:3001/book/'+data.id,{
method : 'put',
body : JSON.stringify({
name : data.name,
price : data.price,
owner_id : data.owner_id
}),
headers : {
'Content-Type' : 'application/json'
}
})
.then(res => res.json())
.then(res => {
console.log("==============修改返回参数:"+JSON.stringify(res));
dispatch(updateBookAction(data))
message.success("修改记录成功")
})
.catch(error => {
message.error("修改记录失败")
})
})
}
}
}
const BookListContainer = connect(
mapStateToProps,
mapDispatchToProps
)(BookList); export default BookListContainer;
//src\containers\UserList.js
import { connect } from 'react-redux';
import UserList from '../components/UserList';
import { deleteUserAction ,addUserAction ,updateUserAction } from '../actions/userActions'; const mapStateToProps = (state) => {
return {
userList : state.userReducer.data
};
} const mapDispatchToProps = (dispatch) => {
return {
deleteUser : (id) => {
dispatch(deleteUserAction(id))
},
addUser : (data) => {
dispatch(addUserAction(data))
},
editUser : (data) => {
dispatch(updateUserAction(data))
}
}
}
const UserListContainer = connect(
mapStateToProps,
mapDispatchToProps
)(UserList); export default UserListContainer;

【react】react-bookManager的更多相关文章

  1. 【前端】react and redux教程学习实践,浅显易懂的实践学习方法。

    前言 前几天,我在博文[前端]一步一步使用webpack+react+scss脚手架重构项目 中搭建了一个react开发环境.然而在实际的开发过程中,或者是在对源码的理解中,感受到react中用的最多 ...

  2. 【优质】React的学习资源

    React的学习资源 github 地址: https://github.com/LeuisKen/react-collection https://github.com/reactnativecn/ ...

  3. 【温故知新】—— React/Redux/React-router4基础知识&独立团Demo

    前言:React专注View层,一切皆组件:全部使用ES6语法,最新版本为React16. Redux是专注于状态管理的库,和react解耦:单一状态,单向数据流.[独立团github地址] 一.Re ...

  4. 【React】react学习笔记03-React组件对象的三大属性-state

    今天晚上学习了React中state的使用,特做此记录,对于学习的方式,博主仍然推荐直接复制完整代码,对着注释观察现象!: 上文中,我列举了两种React自定义组件的声明,这里我拿方式二进行举例: / ...

  5. 【React】react学习笔记02-面向组件编程

    react学习笔记02-面向组件编程 面向组件编程,直白来说,就是定义组件,使用组件. 以下内容则简单介绍下组建的声明与使用,直接复制demo观测结果即可. 步骤: 1.定义组件   a.轻量组件-函 ...

  6. 【独家】React Native 版本升级指南

    前言 React Native 作为一款跨端框架,有一个最让人头疼的问题,那就是版本更新.尤其是遇到大版本更新,JavaScript.iOS 和 Android 三端的配置构建文件都有非常大的变动,有 ...

  7. 【原】react做tab切换的几种方式

    最近搞一个pc端的活动,搞了一个多月,甚烦,因为相比于pc端,更喜欢移动端多一点.因为移动端又能搞我的react了. 今天主要总结一下react当中tab切换的几种方式,因为tab切换基本上都会用到. ...

  8. 【转载】React入门-Todolist制作学习

    我直接看的这个React TodoList的例子(非常好!): http://www.reqianduan.com/2297.html 文中示例的代码访问路径:http://127.0.0.1:708 ...

  9. 【JAVASCRIPT】React入门学习-文本渲染

    摘要 react 学习包括几个部分: 文本渲染 JSX 语法 组件化思想 数据流 文本渲染 1. 纯文本渲染 <!DOCTYPE html> <html> <head&g ...

  10. 【JAVASCRIPT】React + Redux

    摘要 Redux 数据流图 View 层由React 控制, 根据state 变化 刷新渲染组件,作用是根据更新的数据重新渲染组件 Stroe 层其实就是state存储器,作用是更新数据 Dispat ...

随机推荐

  1. PAT甲级——【牛客A1005】

    题目描述 Behind the scenes in the computer's memory, color is always talked about as a series of 24 bits ...

  2. GC 案例收集整理

    1.数组动态扩容  现象:系统一直在做cms gc,但是老生代一直不降下去,但是执行一次jmap -histo:live之后,也就是主动触发一次full gc之后,通过jstat -gcutil来看老 ...

  3. 在scrapy中过滤重复的数据

    当为了确保爬到的数据中没有重复的数据的时候,可以实现一个去重的item pipeline 增加构造器方法,在其中初始化用于对与书名的去重的集合 在process_item方法中,先取出item中要判断 ...

  4. Ubuntu安装CUDA9.2(不更新驱动)

    1.先装驱动,以为安装CUDA时安装最新驱动导致CUDA用不了 sudo apt-get install nvidia-396 2.参考这,安装好CUDA 9.2 https://developer. ...

  5. MapReduce深入理解输入和输出格式(1)-输入分片与记录

    一个输入分片( in put split)就是能够被单个map 操作 处理的输入块. 每一个map 操作只处理一个输入分片,并且一个一个地处理每条记录,也就是一个键/值对.输入分片和记录都是逻辑上的, ...

  6. [转]WPF中Binding的技巧

    在WPF应用的开发过程中Binding是一个非常重要的部分. 在实际开发过程中Binding的不同种写法达到的效果相同但事实是存在很大区别的. 这里将实际中碰到过的问题做下汇总记录和理解. 1. so ...

  7. goland破解

    PyCharm是由著名的JetBrains公司所打造的一款功能强大的Python IDE,它具有一般IDE都具备的功能,并且使用起来非常方便好用.最近需求PyCharm激活码的网友非常多,小编就在这里 ...

  8. vue.js_09_vue-父子组件的传值方法

    1.父向子传递数据 1>定义一个父组件和一个子组件 2>父组件通过v-bind绑定传递的数据  :parentmsg="msg" 3>子组件需要通过 props: ...

  9. utils04_搭建私有Git服务器

    1.远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改.GitHub就是一个免费托管开源代码的远程仓库.但是对于某些视源代码如生命的商业公司来说,既不想公开源代码,又舍不得给G ...

  10. 常用的git操作命令

    整理来源于廖雪峰的git教程https://www.liaoxuefeng.com git: 分布式版本控制系统  本地有完整的代码库,还有远程代码库 svn: 集中式版本控制系统 必须联网时才可提交 ...