Graphql 初体验 第十五章 | #17 Adding Event Features | 学些函数组件中useContext的用法

对应内容:#17 Adding Event Features | Build a Complete App with GraphQL, Node.js, MongoDB and React.js

主要内容

  • 抽离EventList 和 EventItem的逻辑,创建对应的组件
  • 修改登录时的Bug
  • 创建Modal查看Event细节的功能
  • 创建一个Snipper
  • 学习了函数组件中useContext的用法

1 抽离EventList 和 EventItem的逻辑,创建对应的组件,学习了函数组件中useContext的用法

在这里插入图片描述
EventList.js

import EventItem from './EventItem/EventItem';

const EventList = props => {
    const eventItemList = props.events.map(event => {
        return <EventItem
                    event={event}
                    key={event._id}
                    showDetail={props.showDetail}
                    />
    });

    return (
        <ul className="eventlist">{eventItemList}</ul>
    );
}

export default EventList;

EventItem.js

https://zh-hans.reactjs.org/docs/hooks-reference.html#usecontext

const ctx = React.useContext(…React.createContext());

import React from 'react';
import './EventItem.css';
import AuthContext from '../../../../context/auth-context';

const EventItem = props => {
    const ctx = React.useContext(AuthContext);
    return (
        <li className="eventlist__item">
            <div>
                <h1>{props.event.title}</h1>
                <p className="text--highlight">price: {props.event.price}$ - {new Date(props.event.date).toLocaleString()}</p>
            </div>
            <div>
                {
                    ctx.userId === props.event.creator._id ?
                        <p>you are the creator.</p>
                        : <div>
                            <button onClick={props.showDetail.bind(null, props.event._id)}>MORE DETAIL</button>
                        </div>
                }
            </div>
        </li>
    );
}
export default EventItem;

组件抽象做的不是很好,导致每次一改,就要大event.js。

import React, { Component } from 'react';
import Modal from '../components/Modal/Modal';
import Dropback from '../components/Dropback/Dropback';
import AuthContext from '../context/auth-context';
import EventList from '../components/Events/EventList/EventList';
import Snipper from '../components/Snipper/Snipper';

class EventsPage extends Component {
    state = {
        isModalShow: false,
        isLoading: false,
        events: [],
        selectedEvent: null
    }

    static contextType = AuthContext;

    constructor (props) {
        super(props);
        this.titleElRef = React.createRef();
        this.dateElRef = React.createRef();
        this.priceElRef = React.createRef();
        this.descriptionElRef = React.createRef();
    }

    componentDidMount () {
        this.fetchEvents();
    }
    modalStateSwitchHandler = () => {
        this.setState({
            isModalShow: true,
        })
    };

    onCancel = () => {
        this.setState({
            isModalShow: false,
            selectedEvent: null
        })
    };
    onBook = () => {}
    onConfirm = () => {
        const title = this.titleElRef.current.value;
        const date = this.dateElRef.current.value;
        const price = this.priceElRef.current.value;
        const description = this.descriptionElRef.current.value;
        const queryBody = {
            query: `
                mutation {
                    createEvent(eventInput: {title: "${title}", price: ${price}, date: "${date}", description: "${description}"}) {
                        _id
                        title
                        price
                        date
                        description
                        creator {
                            _id
                            email
                        }
                    }
                }
            `
        }
        const token = this.context.token;
        fetch("http://localhost:3030/graphql", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
                "Authorization": "Bearer " + token
            },
            body: JSON.stringify(queryBody),
        })
        .then(response => {
            if (response.status !== 200 && response.status !== 201) {
                throw new Error("request failed!")
            }
            this.setState({
                isModalShow: false
            })
            return response.json();
        })
        .then(data => {
            let newEvents = this.state.events;
            this.setState({
                events: newEvents.concat([data.data.createEvent])
            })
        })
        .catch(err => {
            throw err;
        }) ;
    };
    /**
     * fetch all events
     */
    fetchEvents () {
        this.setState({
            isLoading: true
        });
        const queryBody = {
            query: `
                query {
                    events {
                        _id
                        title
                        price
                        date
                        description
                        creator {
                            _id
                        }
                    }
                }
            `
        }
        fetch("http://localhost:3030/graphql", {
            method: "POST",
            headers: {
                "Content-Type": "application/json",
            },
            body: JSON.stringify(queryBody),
        })
            .then((response) => {
                if (response.status !== 200 && response.status !== 201) {
                    throw new Error("request failed!");
                }
                return response.json();
            })
            .then((data) => {
                this.setState({
                    events: data.data.events
                })
            })
            .catch((err) => {
                throw err;
            })
            .then(() => {
                this.setState({
                    isLoading: false
                });
            },err => {
                this.setState({
                    isLoading: false
                });
                throw err;
            });
    }

    showDetailHandler = (eventId) => {
        this.setState(prevState => {
            const event = prevState.events.find(event => event._id === eventId);
            return {
                selectedEvent: event
            }
        })
    }
    render() {
        return (
            <React.Fragment>
                {this.state.isModalShow && <Dropback />}
                {this.state.isModalShow && <Modal
                    title="Add an event" 
                    onCancel={this.onCancel}
                    onConfirm={this.onConfirm}
                    secondBtnText="Confirm"
                >
                    <form>
                        <div className="form-control">
                            <label htmlFor="title">Title</label>
                            <input type="text" id="title" ref={this.titleElRef} />
                        </div>
                        <div className="form-control">
                            <label htmlFor="date">Date</label>
                            <input type="datetime-local" id="date" ref={this.dateElRef} />
                        </div>
                        <div className="form-control">
                            <label htmlFor="price">Price</label>
                            <input type="number" id="price" ref={this.priceElRef} />
                        </div>
                        <div className="form-control">
                            <label htmlFor="descrip">Description</label>
                            <textarea id="descrip" rows="4" ref={this.descriptionElRef} >
                            </textarea>
                        </div>
                    </form>
                </Modal>}
                {this.state.selectedEvent && <Modal
                    title="Event Detail"
                    onCancel={this.onCancel}
                    onConfirm={this.onBook}
                    secondBtnText="Book"
                >
                    <h1>{this.state.selectedEvent.title}</h1>
                    <h2 className="text--highlight">
                        price: {this.state.selectedEvent.price}$ - {new Date(this.state.selectedEvent.date).toLocaleString()}
                    </h2>
                    <p>
                        {this.state.selectedEvent.description}
                    </p>
                </Modal>}
                <div>
                    <h1>The events Page</h1>
                    {this.context.token && <button onClick={this.modalStateSwitchHandler}>Add Event</button>}
                </div>
                {
                    this.state.isLoading ? <Snipper /> 
                    : <div>
                        <EventList events={this.state.events} showDetail={this.showDetailHandler}/>
                    </div>
                }
            </React.Fragment>
        );
    }
}

export default EventsPage;

2 登录时的BUG

在这里插入图片描述

3 Snipper

https://loading.io/css

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值