【react】react-bookManager
作者可能是本意想要做一个图书管理系统,不过添加书籍的时候报错,所以简单的页面我们简单的看看
先上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的更多相关文章
- 【前端】react and redux教程学习实践,浅显易懂的实践学习方法。
前言 前几天,我在博文[前端]一步一步使用webpack+react+scss脚手架重构项目 中搭建了一个react开发环境.然而在实际的开发过程中,或者是在对源码的理解中,感受到react中用的最多 ...
- 【优质】React的学习资源
React的学习资源 github 地址: https://github.com/LeuisKen/react-collection https://github.com/reactnativecn/ ...
- 【温故知新】—— React/Redux/React-router4基础知识&独立团Demo
前言:React专注View层,一切皆组件:全部使用ES6语法,最新版本为React16. Redux是专注于状态管理的库,和react解耦:单一状态,单向数据流.[独立团github地址] 一.Re ...
- 【React】react学习笔记03-React组件对象的三大属性-state
今天晚上学习了React中state的使用,特做此记录,对于学习的方式,博主仍然推荐直接复制完整代码,对着注释观察现象!: 上文中,我列举了两种React自定义组件的声明,这里我拿方式二进行举例: / ...
- 【React】react学习笔记02-面向组件编程
react学习笔记02-面向组件编程 面向组件编程,直白来说,就是定义组件,使用组件. 以下内容则简单介绍下组建的声明与使用,直接复制demo观测结果即可. 步骤: 1.定义组件 a.轻量组件-函 ...
- 【独家】React Native 版本升级指南
前言 React Native 作为一款跨端框架,有一个最让人头疼的问题,那就是版本更新.尤其是遇到大版本更新,JavaScript.iOS 和 Android 三端的配置构建文件都有非常大的变动,有 ...
- 【原】react做tab切换的几种方式
最近搞一个pc端的活动,搞了一个多月,甚烦,因为相比于pc端,更喜欢移动端多一点.因为移动端又能搞我的react了. 今天主要总结一下react当中tab切换的几种方式,因为tab切换基本上都会用到. ...
- 【转载】React入门-Todolist制作学习
我直接看的这个React TodoList的例子(非常好!): http://www.reqianduan.com/2297.html 文中示例的代码访问路径:http://127.0.0.1:708 ...
- 【JAVASCRIPT】React入门学习-文本渲染
摘要 react 学习包括几个部分: 文本渲染 JSX 语法 组件化思想 数据流 文本渲染 1. 纯文本渲染 <!DOCTYPE html> <html> <head&g ...
- 【JAVASCRIPT】React + Redux
摘要 Redux 数据流图 View 层由React 控制, 根据state 变化 刷新渲染组件,作用是根据更新的数据重新渲染组件 Stroe 层其实就是state存储器,作用是更新数据 Dispat ...
随机推荐
- JS-jquery 获取当前点击的对象
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...
- hibernate抓取策略
抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略.抓取策略可以在O/R映射的 ...
- 让html里的js脚本延迟5秒运行
setTimeout( function(){ //add your code}, 5 * 1000 );//延迟5000毫米
- jQuery实现textarea高度根据内容自适应
//jQuery实现textarea高度根据内容自适应 $.fn.extend({ txtaAutoHeight: function () { return this.each(function () ...
- 7.Spring切入点的表达式和通知类型
1.切入点的表达式 表达式格式: execution([修饰符] 返回值类型 包名.类名.方法名(参数)) 其他的代替: <!-- 完全指定一个方法 --> <!-- <aop ...
- set_clock_latency
set_clock_latancy用于定于虚拟时钟与真实时钟的延时 考虑最糟糕的情况,评估setup时数据会使用最大延时,时钟使用最小延时:评估hold时,数据使用最小延时,时钟使用最大延时.
- C语言处理字符串及内存操作
字符串处理函数 1.字符串长度 strlen表示包含的字符的个数,size_t strlen(char cosnt *string), 返回的是size_t类型,它是无符号整数类型,在表达式中进行运算 ...
- typescript使用小结
1. typescript使得js在书写的过程中有了参数类型的限制在 传参的过程中变得严格,减少了不必要的错误的发生 2. tslint同时也兼备了一部分eslint的作用,在一定程度上我们使用tsl ...
- OpenCV cvReleaseImage把图像怎么样了?
cvReleaseImage(img)和free.delete相同,只是把该指针img所指的内存给释放掉,但并没有把img指针本身干掉,其地址仍然不变(非NULL),只是该地址对应的内存是垃 ...
- 【DM642学习笔记五】FVID驱动模型 API函数
1.FVID_control 作用:发送一个控制命令到mini_driver 语法: status = FVID_control(fvidChan, cmd, args); 参数: FVID_Hand ...