新手。
我有一个名为Client的redux表单组件。该表单中有一个名为Address
的子组件。在客户端中调用Address
,如下所示:
<FormSection name="Address">
<Address />
</FormSection>
Address
的格式为AddressContainer
和Address
。
我正在为Client redux表单设置初始值,如下所示:
let ClientForm = reduxForm({
form: CLIENT_FORM_NAME
})(Client);
let ClientForm2 = connect(
(state, ownProps) => ({
initialValues: ownProps.isEditMode ? state.editClient : {}, // pull initial values from client reducer
enableReinitialize: true
}),
{ reducer } // bind client loading action creator
)(ClientForm);
export default ClientForm2;
但是Address
组件没有设置任何初始状态。
你如何以redux形式将初始状态从主窗体传递到其子组件 - 在这种情况下是Address
?
AddressContainer:
import React, { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { Field, change } from "redux-form";
import { Col, Panel, Row } from "react-bootstrap";
import Select from "react-select";
import Address from "./address";
import { getSuburbs, ensureStateData } from "./actions";
import FormField from "../formComponents/formField";
import TextField from "../formComponents/textField";
import StaticText from "../formComponents/staticText";
import { CLIENT_FORM_NAME } from "../clients/client/client";
export class AddressContainer extends Component {
static contextTypes = {
_reduxForm: PropTypes.object.isRequired
};
constructor(props, context) {
super(props, context);
this.state = {
selectedSuburb: null
};
}
// Manage Select.Async for new data request - for suburbs.
handleSuburbSearch = query => {
const { addressData } = this.props;
const companyStateId = addressData.companyStateId;
if (!query || query.trim().length < 2) {
return Promise.resolve({ options: [] });
}
const queryString = {
query: query,
companyStateId: companyStateId
};
return getSuburbs(queryString).then(data => {
return { options: data };
});
};
// Update the current state with the selected suburb.
onSuburbStateChange = value => {
this.setState({ selectedSuburb: value });
};
componentDidMount() {
this.props.ensureStateData();
}
render() {
const { initialValues, addressData, updatePostcodeValue } = this.props;
const { value } = this.state;
const sectionPrefix = this.context._reduxForm.sectionPrefix;
if (addressData.isLoading || !addressData.states.length) {
return <p>Loading</p>;
}
if (addressData.error) {
return <p>Error loading data</p>;
}
console.group("InitalValues Address");
const companyStateId = addressData.companyStateId;
console.log("companyStateId:", companyStateId);
initialValues.Address = {
...initialValues.Address,
state: addressData.states.find(
option => option.stateId === companyStateId
)
};
console.log(
"addressData.states.Find: ",
addressData.states.find(option => option.stateId === companyStateId)
);
console.log("addressData.states: ", initialValues.Address.state);
console.log("initialValues.Address: ", initialValues.Address);
console.log("initialValues: ", initialValues);
console.groupEnd();
return (
<Address
initialValues={initialValues}
handleSuburbSearch={this.handleSuburbSearch}
onSuburbStateChange={this.onSuburbStateChange}
updatePostcodeValue={updatePostcodeValue}
addressData={addressData}
sectionPrefix={sectionPrefix}
/>
);
}
}
const mapStateToProps = state => ({
initialValues: state.editClient,
companyStateId: state.companyStateId,
addressData: state.addressData
});
const mapDispatchToProps = dispatch => ({
ensureStateData: () => dispatch(ensureStateData()),
getSuburbs: values => dispatch(getSuburbs(values)),
updatePostcodeValue: (postcode, sectionPrefix) =>
dispatch(
change(
CLIENT_FORM_NAME,
`${sectionPrefix ? sectionPrefix + "." : ""}postcode`,
postcode
)
)
});
export default connect(mapStateToProps, mapDispatchToProps)(AddressContainer);
地址:
import React, { Component, PropTypes } from "react";
import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form";
import { Col, Panel, Row } from "react-bootstrap";
import Select from "react-select";
import { getSuburbs } from "./actions";
import FormField from "../formComponents/formField";
import TextField from "../formComponents/textField";
import StaticText from "../formComponents/staticText";
import reducer from "../address/reducer";
export const Address = props => {
const {
initialValues,
handleSuburbSearch,
companyValue,
onSuburbStateChange,
updatePostcodeValue,
addressData,
sectionPrefix
} = props;
const { reset } = props;
{
console.log("PROPS ADDRESS DATA: ", props.stateData);
console.log("PROPS INITIALVALIES: ", props.initialValues);
console.log("COMPANY VALUE: ", companyValue);
}
return (
<Panel header={<h3>Client - Address Details</h3>}>
<Row>
<Field
component={TextField}
name="address1"
id="address1"
type="text"
label="Address Line 1"
placeholder="Enter street 1st line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
<Field
component={TextField}
name="address2"
id="address2"
type="text"
label="Address Line 2"
placeholder="Enter street 2nd line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props;
const {
fieldCols,
labelCols,
controlCols,
label,
inputClass
} = props;
// The props we want the inner Select textbox to have.
const { name, onChange } = input;
const onStateChange = state => {
console.log("onStateChange", state);
onChange(state);
};
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select
name={name}
onChange={onStateChange}
placeholder="Select state"
valueKey="id"
options={addressData.states}
labelKey="stateLabel"
optionRenderer={option =>
`${option.stateShortName} (${option.stateName})`}
value={input.value}
selectValue={
Array.isArray(input.value) ? input.value : undefined
}
/>
</FormField>
);
}}
name="state"
id="state"
label="State."
fieldCols={6}
labelCols={3}
controlCols={6}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props;
const {
fieldCols,
labelCols,
controlCols,
label,
inputClass
} = props;
// The props we want the inner Select.Async textbox to have.
const { name, value, onChange, onBlur, onFocus } = input;
// A suburb was selected so "onChange" is updated along
//with the static form component "Postcode".
const onSuburbChange = value => {
onSuburbStateChange(value);
input.onChange(value);
updatePostcodeValue(value ? value.postcode : null, sectionPrefix);
};
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select.Async
{...input}
onChange={onSuburbChange}
placeholder="Select suburb"
valueKey="id"
labelKey="suburbName"
value={input.value}
loadOptions={handleSuburbSearch}
backspaceRemoves={true}
/>
</FormField>
);
}}
name="suburb"
id="suburb"
label="Suburb."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field
component={StaticText}
name="postcode"
id="postcode"
label="Postcode."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
</Panel>
);
};
Address.propTypes = {
handleSuburbSearch: PropTypes.func.isRequired,
onSuburbStateChange: PropTypes.func.isRequired
};
const AddressForm = reduxForm({
form: "Address"
})(Address);
let AddressForm2 = connect(
(state, ownProps) => ({
initialValues: state.editClient, // pull initial values from client reducer
enableReinitialize: true
}),
{ reducer } // bind client loading action creator
)(AddressForm);
export default Address;
来自Chrome中Redux工具的state.editClient:
请注意,address1
,suburb
和postcode
都有值及其在Address
组件中未显示的值...