【react】react-bookManager

作者可能是本意想要做一个图书管理系统,不过添加书籍的时候报错,所以简单的页面我们简单的看看
先上github地址:https://github.com/hesisi/react-bookManager
看package.json文件是有用到中间件的,心里多了点期待,也许帮它修复好bug也行呢
先看页面

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

//srcindex.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;
//srcactionsuserActions.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
    }
}
//srccomponentsSearchInput.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={{ 400 ,marginBottom :20}}
                            enterButton = "搜索"
                        />
                    </Col>
                    <Col span={3}>
                        <Button type="primary" onClick={this.props.addHandle}>添加</Button>
                    </Col>
                </Row>
                
            </div>
        );
    }
}

export default SearchInput;
//srccomponentsForm.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);

//srccomponentsUserAdd.js
import React from 'react';

class UserAdd extends React.Component{
    render(){
        return (
            <div>添加用户</div>
        );
    }
}

export default UserAdd;

//srccomponentsBookList.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;
//srccomponentsForm.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);
//srccontainersBookList.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;
//srccontainersUserList.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;
原文地址:https://www.cnblogs.com/smart-girl/p/10974460.html