我正在构建一个分成多个选项卡的表单。我正在使用 React Context API 来捕获表单输入的状态并在 Provider 中设置状态。这在表单输入位置的我的消费者中很好。但是,我在最后一个选项卡中的表单中也有一个视图,我可以在所有步骤中查看表单的输入。该位置的 Provider 仅显示 React Dev Tools 中的默认状态值,因此无法更新 Consumer。我不确定为什么 Provider 的第二个实例中的状态没有被更新以作为道具传递给审查部分。我createContext()
已从提供程序导出并将其导入我的评论部分消费者和我的表单输入部分消费者。
继承人一些代码:
提供者:
import React, { Component } from "react";
import moment from 'moment';
import PropTypes from 'prop-types';
const defaultDateState = moment();
const daysWeek = [
{name: 'All'},
{name: 'Sunday'},
{name: 'Monday'},
{name: 'Tuesday'},
{name: 'Wednesday'},
{name: 'Thursday'},
{name: 'Friday'},
{name: 'Saturday'}
];
const descMaxChars = 512;
export const BasicContext = React.createContext();
class BasicInfoProvider extends Component {
state = {
basicDesc: null,
startDate: defaultDateState,
endDate: defaultDateState,
daysOfWeek: null,
dayWeek: [],
dayWeekOptions: daysWeek,
descCharsLeft: descMaxChars,
};
//handle dates
handleChangeStart = (date) => {
console.log(date);
this.setState({
startDate: date
});
}
handleChangeEnd = (date) => {
this.setState({
endDate: date
});
}
handleChangeDesc = (e) => {
var input = e.target.value;
this.setState({
basicDesc: input,
descCharsLeft: descMaxChars - input.length
});
}
handleDaysWeek = (e) => {
console.log('days week selection', e.target.value)
const daySelection = e.target.value;
let daySelectionArr;
if(this.state.dayWeek.indexOf(daySelection) > -1) {
daySelectionArr = this.state.dayWeek.filter(s => s !== daySelection)
} else {
daySelectionArr = [...this.state.dayWeek, daySelection];
}
this.setState({ dayWeek: daySelectionArr });
}
render(){
return(
<React.Fragment>
<BasicContext.Provider value={{
state: this.state,
actions: {
handleChangeDesc: this.handleChangeDesc,
handleChangeEnd: this.handleChangeEnd,
handleChangeStart: this.handleChangeStart,
handleDaysWeek: this.handleDaysWeek
},
}}>
{this.props.children}
</BasicContext.Provider>
</React.Fragment>
)
}
}
export const contextTypes = {
basicDesc: PropTypes.string,
startDate: PropTypes.number,
endDate: PropTypes.number,
daysOfWeek: PropTypes.string,
dayWeek: PropTypes.array,
dayWeekOptions: PropTypes.array,
descCharsLeft: PropTypes.number,
}
export default BasicInfoProvider;
表单输入消费者:
import React, { Component } from "react";
import DateElement from "../DateElement";
import { Button, ButtonToolbar, FormGroup, ControlLabel, Checkbox, FormControl, HelpBlock, Modal, Glyphicon } from "react-bootstrap";
import DatePicker from 'react-datepicker';
import Select from 'react-select';
import { BasicContext, contextTypes } from './BasicInfoProvider';
import {getContext} from '../../utilities/GetContext';
import 'react-datepicker/dist/react-datepicker.css';
import 'react-select/dist/react-select.css';
class BasicInfoForm extends Component {
render(){
return(
<section className="basic-info-section">
<BasicContext.Consumer >
{({state, actions}) => (
<React.Fragment>
<div className="row">
<FormGroup
controlId="desc-field"
>
<h3>Description</h3>
<FormControl
type="textarea"
value={state.basicDesc}
placeholder="Enter Your Description Here"
onChange={actions.handleChangeDesc}
maxLength="512"
/>
<FormControl.Feedback />
<HelpBlock>Characters left: {state.descCharsLeft}</HelpBlock>
</FormGroup>
</div>
<hr/>
<div className="row">
<div className="date-picker-duo col-sm-6">
<div className="col-xs-6">
<h3>Start Date</h3>
<DatePicker
inline
selected={state.startDate}
selectsStart
onChange={actions.handleChangeStart}
placeholderText='Click to select a date'
className="start-date-field"
/>
</div>
<div className="col-xs-6">
<h3>End Date</h3>
<DatePicker
inline
selected={state.endDate}
selectsend
onChange={actions.handleChangeEnd}
placeholderText='Click to select a date'
className="end-date-field"
/>
</div>
</div>
<FormGroup bsClass="col-sm-6" controlId="formControlsSelectMultiple">
<h3 className="days-checkbox-title">Days of the Week</h3>
{state.dayWeekOptions.map((day) => {
return(
<div className="weekday-checkbox col-xs-3">
<input
value={day.name}
onChange={actions.handleDaysWeek}
type="checkbox"
id={day.name}
key={day.name} />
<label htmlFor={day.name}>{day.name}</label>
</div>
)
})}
</FormGroup>
</div>
</React.Fragment>
)}
</BasicContext.Consumer>
</section>
);
}
};
export default BasicInfoForm = getContext(contextTypes)(BasicInfoForm);
评论部分消费者
import React from 'react';
import { BasicContext, contextTypes } from './BasicInfoProvider';
import {getContext} from '../../utilities/GetContext';
const finalReview = (props) => {
return(
<div className="row">
<h2>So you're all done with your new Promotion?</h2>
<p>Take another look at what you're about to submit and if you like how it looks, send it on through!</p>
<div className="well">
<header className="review-section-header">
<h3>Basic Info </h3>
<span className="review-edit" onClick={() => this.handleTabSelect(1)}>Edit Section</span>
</header>
<BasicContext.Consumer >
{({state}) => (
<div className="review-group">
<p>
<span className="review-title">Description: </span>
<span className="review-value">{state.basicDesc}</span>
</p>
<p>
<span className="review-title">Promotion Start Date: </span>
<span className="review-value">{state.startDate.toString()}</span>
</p>
<p>
<span className="review-title">Promotion End Date: </span>
<span className="review-value">{state.endDate.toString()}</span>
</p>
<p>
<span className="review-title">Promotion Days of the Week: </span>
<span className="review-value">
{state.dayWeek.map((day) => {
return( `${day}, `)
})}
</span>
</p>
</div>
)}
</BasicContext.Consumer>
</div>
</div>
)
}
const FinalReview = getContext(contextTypes)(finalReview);
export default FinalReview;
getContext
只是我传递 ContextTypes 的一个简单的 HOC。
BasicInfoForm
是表单的子组件,存在于表单内部的一个选项卡中,但提供者是直接去的,所以我认为选项卡是无关紧要的。
我的期望是BasicInfoProvider
当BasicInfoForm
调用传入的函数时将更新,并且更新将反映在使用的任何地方BasicInfoProvider
,但是当它用于FinalReview
组件时不会发生这种情况