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

先上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. <数据库>MySQL补充( 查询)

    show create table 表名 \G;(查看创建的属性) alter table 表名 auto_increment=xx;(修改自增起始值) set session auto_increm ...

  2. css 渐变背景

    background: linear-gradient(left,#fa7f6d, #fc5e7f); left: 从左边开始

  3. Redis Set ZSet类型的学习

  4. Redis集群搭建详细过程整理备忘

    三.安装配置 1.环境 使用2台centos服务器,每台机器上部署3个实例,集群为三个主节点与三个从节点: 192.168.5.144:6380 192.168.5.144:6381 192.168. ...

  5. Numpy数据的操作 * dot() multiply() 的区别

    使用numpy时,跟matlab不同: 1.* dot() multiply() 对于array来说,* 和 dot()运算不同 *是每个元素对应相乘 dot()是矩阵乘法 对于matrix来说,*  ...

  6. 推荐5款超实用的.NET性能分析工具

    虽然.NET框架号称永远不会发生内存泄漏,原因是引入了内存回收机制.但在实际应用中,往往我们分配了对象但没有释放指向该对象的引用,导致对象永远无法释放.最常见的情况就是给对象添加了事件处理函数,但当不 ...

  7. 主成分分析(PCA)原理详解_转载

    一.PCA简介 1. 相关背景 在许多领域的研究与应用中,往往需要对反映事物的多个变量进行大量的观测,收集大量数据以便进行分析寻找规律.多变量大样本无疑会为研究和应用提供了丰富的信息,但也在一定程度上 ...

  8. Extjs4 的一些语法 持续更新中

    一.给GridPanel增加成两行toolbar tbar: { xtype: 'container', layout: 'anchor', defaults: {anchor: '0'}, defa ...

  9. jeecmsv9-adminVue 打包出错

    F:\jeecms\jeecmsv9-adminVue>node build\build.js - building for production...Error processing file ...

  10. 修改mysql字段类型,修改字段名

    修改字段类型(数据类型,长度,默认值) alter table user modify user_name 类型 修改字段名 方法一:alter table 表 change 旧字段名 新字段名 新数 ...