代码之家  ›  专栏  ›  技术社区  ›  Toma Tomov

子组件中未定义的上下文属性(当它明显存在时)

  •  0
  • Toma Tomov  · 技术社区  · 4 年前

    我的主要父组件:

    import React, {Component} from 'react';
    
    import {Content} from './styles';
    
    import {toast} from 'react-toastify';
    
    import Steps from './Steps';
    
    import PropertyInformation from './Information';
    import Taxes from './Taxes';
    import Sites from './Sites';
    import Payment from './Payment';
    import {SanctumContext} from "react-sanctum";
    
    class Property extends Component {
    
        static contextType = SanctumContext;
    
        constructor(props) {
            super(props);
    
            this.state = {
                step: 1,
                completed: [],
                property: null
            };
    
            this.saveDraft = this.saveDraft.bind(this);
            this.nextStep = this.nextStep.bind(this);
        }
    
        saveDraft(data) {
            if (this.state.step == 1) {
                const draft = {
                    pname: data.pname,
                    image: data.image,
                    email: data.email,
                    website: data.website,
                    fax: data.fax,
                    phone: data.phone,
                    checkin: data.checkin,
                    checkout: data.checkout,
                    address: data.address,
                    country: data.country,
                    state: data.state,
                    city: data.city,
                    latitude: data.latitude,
                    longitude: data.longitude
                };
            }
    
            // call to save draft
    
            toast.success('Progress saved!')
        }
    
        componentDidMount() {
            if (this.props.match.params.id) {
                axios.get("/api/v1/getProperty/"+this.props.match.params.id)
                    .then(response => {
                        this.context.propertyObject= response.data
                    })
            }
        }
    
        nextStep(data) {
            if (this.state.step == 1) {
                const info = {
                    pname: data.pname,
                    image: data.image,
                    email: data.email,
                    website: data.website,
                    fax: data.fax,
                    phone: data.phone,
                    checkin: data.checkin,
                    checkout: data.checkout,
                    address: data.address,
                    country: data.country,
                    state: data.state,
                    city: data.city,
                    latitude: data.latitude,
                    longitude: data.longitude
                };
            }
    
            if (this.state.step == 2) {
                const taxes = data.taxes;
            }
    
            if (this.state.step == 4) {
                const info = {
                    timeBefore: data.timeBefore,
                    timeBeforeType: data.timeBeforeType,
                    pets: data.pets,
                    currency: data.currency,
                    americanExpress: data.americanExpress,
                    maestro: data.currency,
                    visa: data.visa,
                    discover: data.discover,
                    euro: data.euro,
                    unionPay: data.unionPay,
                    diners: data.diners,
                    jcb: data.jcb,
                    invoiceName: data.invoiceName
                };
            }
    
            // call to save data
            const completed = this.state.completed;
    
            completed.push(this.state.step);
    
            this.setState({
                step: this.state.step + 1,
                completed: completed
            });
    
            toast.success('Progress saved!')
        }
    
        render() {
            return(
                <Content>
                    <Steps
                        step={this.state.step}
                        completed={this.state.completed}
                    />
    
                    {this.state.step == 1 &&
                        <PropertyInformation
                            saveDraft={(data) => this.saveDraft(data)}
                            nextStep={(data) => this.nextStep(data)}
                        />
                    }
    
                    {this.state.step == 2 &&
                        <Taxes
                            previous={() => this.setState({step: this.state.step - 1})}
                            saveDraft={(data) => this.saveDraft(data)}
                            nextStep={(data) => this.nextStep(data)}
                        />
                    }
    
                    {this.state.step == 3 &&
                        <Sites
                            previous={() => this.setState({step: this.state.step - 1})}
                            nextStep={() => this.setState({step: this.state.step + 1})}
                        />
                    }
    
                    {this.state.step == 4 &&
                        <Payment
                            previous={() => this.setState({step: this.state.step - 1})}
                            saveDraft={(data) => this.saveDraft(data)}
                            nextStep={(data) => this.nextStep(data)}
                        />
                    }
                </Content>
            )
        }
    }
    
    export default Property;
    

    以及我的财产信息部分:

    import React, {Component} from 'react';
    import InputMask from 'react-input-mask';
    import Select from 'react-select';
    import {FaCloudUploadAlt} from 'react-icons/fa'
    
    import selectStyles from '../../../styles/selectInputStyles';
    
    import {Content, Half, Form, ImageInput, ImagePreview, HalfInput, Controls, Span} from './styles';
    
    import Location from './Location';
    import {SanctumContext} from "react-sanctum";
    
    class PropertyInformation extends Component {
    
        static contextType = SanctumContext;
    
        constructor(props) {
            super(props);
    
            this.state = {
                pname: null,
                image: null,
                imageURL: null,
                email: null,
                website: null,
                fax: null,
                phone: null,
                checkin: null,
                checkout: null,
                address: null,
                country: null,
                state: null,
                city: null,
                latitude: null,
                longitude: null,
                countries: null
            }
    
            this.loadCountries = this.loadCountries.bind(this);
            this.updateImage = this.updateImage.bind(this);
            this.updateCountry = this.updateCountry.bind(this);
            this.updateState = this.updateState.bind(this);
            this.submit = this.submit.bind(this);
        }
    
        async loadCountries() {
            await axios.get("/api/v1/countries").then(response => {
                this.setState({countries: response.data});
            })
            .catch(err => {
                message("error", "Countries couldn't be loaded")
            })
        }
    
        updateImage(image) {
            const reader = new FileReader();
            const url = reader.readAsDataURL(image);
    
            reader.onloadend = () => {
                this.setState({
                    imageURL: [reader.result]
                })
            };
        }
    
        async updateCountry(selection) {
            await axios.get("/api/v1/states/"+selection.value).then(response => {
                this.setState({
                    country: selection.value,
                    states: response.data
                });
            })
            .catch(err => {
                message("error", "States couldn't be loaded")
            })
        }
    
        async updateState(selection) {
            await axios.get("/api/v1/cities/"+selection.value).then(response => {
                this.setState({
                    state: selection.value,
                    cities: response.data
                });
            })
            .catch(err => {
                message("error", "Cities couldn't be loaded")
            })
        }
    
        submit(e) {
            e.preventDefault();
            const images = e.target.files
            let form = new FormData()
            form.append("image", images)
            axios.post("/api/v1/set-information", {
                user_id: this.context.user.id,
                name: this.state.pname,
                imageUrl: this.state.imageUrl,
                email: this.state.email,
                website: this.state.website,
                phone: this.state.phone,
                fax: this.state.fax,
                check_in: this.state.checkin,
                check_out: this.state.checkout,
                address: this.state.address,
                country: this.state.country,
                state: this.state.state,
                city: this.state.city,
                zip: this.state.zip,
                lat: this.state.latitude,
                long: this.state.longitude,
            })
            .then(response => {
                if (response.status === 200) {
                    this.context.property = response.data.id
                    this.props.nextStep(this.state);
                }
            })
            .catch(err => {
                if (err.response.status === 422) {
                    message("error", err.response.message)
                }
            })
        }
    
        componentDidMount() {
            console.log("OUT", this.context.propertyObject)
            if (this.context.propertyObject) {
                console.log("IN", this.context.propertyObject)
                /*console.log("ASDASDAasdassda")
                this.setState({phone: this.context.property.phone}, function(){
                    console.log(this.state.phone)
                })*/
            }
            this.loadCountries();
        }
    
        render() {
            console.log("PHONE", this.state.phone)
            return(
                <Content>
                    <Form>
                        <form onSubmit={(e) => this.submit(e)}>
                            <Half>
                                <p>Property Name*</p>
                                <input onChange={(e) => this.setState({pname: e.target.value})} required></input>
    
                                {!this.state.imageURL &&
                                <ImageInput>
                                    <FaCloudUploadAlt />
                                    <p>Upload main image</p>
                                    <input type="file" value={this.state.image} onChange={e => this.updateImage(e.target.files[0])} />
                                </ImageInput>
                                }
    
                                {this.state.imageURL &&
                                <ImagePreview>
                                    <img src={this.state.imageURL} />
                                    <p onClick={() => this.setState({image: null, imageURL: null})}>Remove</p>
                                </ImagePreview>
                                }
    
                                <p>E-mail</p>
                                <input onChange={(e) => this.setState({email: e.target.value})}></input>
    
                                <p>Website</p>
                                <input
                                    onChange={(e) => this.setState({website: e.target.value})}></input>
    
                                <section>
                                    <HalfInput>
                                        <p>Phone number*</p>
                                        <InputMask
                                            onChange={(e) => this.setState({phone: e.target.value})}
                                            required
                                            mask="+999 99 999 99"
                                            alwaysShowMask
                                            maskChar="_"
                                        />
                                    </HalfInput>
                                    <HalfInput>
                                        <p>Fax</p>
                                        <InputMask
                                            onChange={(e) => this.setState({fax: e.target.value})}
                                            required
                                            mask="+999 99 999 99"
                                            alwaysShowMask
                                            maskChar="_"
                                        />
                                    </HalfInput>
                                </section>
    
                                <section>
                                    <HalfInput>
                                        <p>Check-in*</p>
                                        <InputMask
                                            onChange={(e) => this.setState({checkin: e.target.value})}
                                            required
                                            mask="99:99"
                                            alwaysShowMask
                                            maskChar="_"
                                        />
                                    </HalfInput>
    
                                    <HalfInput>
                                        <p>Check-out*</p>
                                        <InputMask
                                            onChange={(e) => this.setState({checkout: e.target.value})}
                                            required
                                            mask="99:99"
                                            alwaysShowMask
                                            maskChar="_"
                                        />
                                    </HalfInput>
                                </section>
                            </Half>
                            <Half>
                                <p>Address*</p>
                                <input onChange={e => this.setState({address: e.value})} required></input>
    
                                <section>
                                    <HalfInput>
                                        <p>Country*</p>
                                        <Select
                                            options={this.state.countries}
                                            styles={selectStyles}
                                            onChange={e => this.updateCountry(e)}
                                            placeholder=''
                                        />
                                    </HalfInput>
    
                                    <HalfInput>
                                        <p>State*</p>
                                        <Select
                                            options={this.state.states}
                                            styles={selectStyles}
                                            onChange={e => this.updateState(e)}
                                            placeholder=''
                                        />
                                    </HalfInput>
                                </section>
    
                                <section>
                                    <HalfInput>
                                        <p>City*</p>
                                        <Select
                                            options={this.state.cities}
                                            styles={selectStyles}
                                            onChange={e => this.setState({city: e.value})}
                                            placeholder=''
                                        />
                                    </HalfInput>
    
                                    <HalfInput>
                                        <p>Zip*</p>
                                        <input onChange={(e) => this.setState({zip: e.target.value})} required></input>
                                    </HalfInput>
                                </section>
    
                                <section>
                                    <HalfInput>
                                        <p>Latitude</p>
                                        <input onChange={(e) => this.setState({latitude: e.target.value})}></input>
                                    </HalfInput>
    
                                    <HalfInput>
                                        <p>Longitude</p>
                                        <input onChange={(e) => this.setState({longitude: e.target.value})}></input>
                                    </HalfInput>
                                </section>
    
                                <Location
                                    address={`${this.state.country}, ${this.state.state}, ${this.state.city}, `}
                                />
    
                                <Controls>
                                    <Span disabled>Previous</Span>
                                    <Span onClick={() => this.props.saveDraft(this.state)}>Save as draft</Span>
    
                                    <button>Proceed</button>
                                </Controls>
                            </Half>
                        </form>
                    </Form>
                </Content>
            )
        }
    }
    
    export default PropertyInformation;
    

    上下文中有一个属性 propertyObject contenxt 在孩子身上显示 属性对象 有并装载了数据。但如果我想达到我得到 undefined . this.context.propertyObject

    0 回复  |  直到 4 年前
        1
  •  1
  •   Benjamin    4 年前

    看起来您正试图直接修改使用者内部的上下文对象。这是行不通的。您需要在上下文值提供给React应用程序时修改它。

    作为一项规则,上下文使用者不得改变或修改上下文值。

    现在,我不熟悉react sanctum,但是在简要回顾了文档之后,并不意味着您可以访问上下文提供者。

    您需要找到一种不同的方法将propertyObject传递给子组件。传递道具,或者创建一个新上下文并在子组件上方呈现context.Provider。

    https://reactjs.org/docs/context.html#classcontexttype