问题
I need to be able to combine this into one function. There are 2 separate arrays...
{this.state.telephoneType.map((telephoneType, ttidx) => ())}
and...
{this.state.telephone.map((telephone, tidx) => ())}
Basically, this is because I have a button which concatenates the 2 functions and it has to be outside the row class (MDBRow) so the UI doesn't break.
<MDBRow className="grey-text no-gutters my-2">
{this.state.telephoneType.map((telephoneType, ttidx) => (
<MDBCol md="4" className="mr-2">
<select
key={ttidx}
defaultValue={telephoneType.name}
onChange={this.handleTelephoneTypeChange(ttidx)}
className="browser-default custom-select">
<option value="Mobile">Mobile</option>
<option value="Landline">Landline</option>
<option value="Work">Work</option>
</select>
</MDBCol>
))}
{this.state.telephone.map((telephone, tidx) => (
<MDBCol md="7" className="d-flex align-items-center">
<input
value={telephone.name}
onChange={this.handleTelephoneChange(tidx)}
placeholder={`Telephone No. #${tidx + 1}`}
className="form-control"
/>
<MDBIcon icon="minus-circle"
className="mr-0 ml-2 red-text"
onClick={this.handleRemoveTelephone(tidx)} />
</MDBCol>
))}
</MDBRow>
<div className="btn-add" onClick={this.handleAddTelephone}>
<MDBIcon className="mr-1" icon="plus-square" />
Add Telephone
</div>
This is the handleAddTelephone function...
handleAddTelephone = () => {
this.setState({
telephone: this.state.telephone.concat([{ name: "" }]),
telephoneType: this.state.telephoneType.concat([{ name: "" }])
});
};
and the Constructor looks like this...
class InstallerAdd extends React.Component {
constructor() {
super();
this.state = {
role: "Installer",
name: "",
telephoneType: [{ name: "" }],
telephone: [{ name: "" }],
tidx: "",
emailType: [{ email: "" }],
email: [{ email: "" }],
eidx: "",
notes: ""
};
}
}
Can I nest one array inside the other? I'm not sure how to do this so any advice appreciated. Thanks.
Edit: These are the 2 telephone functions which need to be 1 function... I have updated with new nested array for each
handleTelephoneChange = tidx => evt => {
const newTelephone = this.state.telephone.type.map((telephone, tsidx) => {
if (tidx !== tsidx) return telephone;
return { ...telephone, name: evt.target.value };
});
this.setState({ telephone: newTelephone }, () => {
// get state on callback
console.log(this.state.telephone.number[tidx].name)
}
);
};
handleTelephoneTypeChange = ttidx => evt => {
const newTelephoneType = this.state.telephone.number.map((telephoneType, ttsidx) => {
if (ttidx !== ttsidx) return telephoneType;
return { ...telephoneType, name: evt.target.value };
});
this.setState({ telephoneType: newTelephoneType }, () => {
// get state on callback
console.log(this.state.telephone.type[ttidx].name)
}
);
};
My constructor now looks like this...
class InstallerAdd extends React.Component {
constructor() {
super();
this.state = {
role: "Installer",
name: "",
telephone: {
type: [{ name: "" }],
number: [{ name: "" }]
},
tidx: "",
emailType: [{ email: "" }],
email: [{ email: "" }],
eidx: "",
notes: ""
};
}
回答1:
Although I still don't quite understand how your UI "breaks" (video won't load for me), I hope I can help.
Basically the short answer about trying to map two arrays singly is that you can't (well, shouldn't), but with some assumptions about the two array's length always being equal and the order is the same between the two, then you can map over the first array and use the passed index
from the map function to access the second.
arrayA.map((itemFromA, index) => {
// do stuff with item from A
const itemFromB = arrayB[index];
// do stuff with item from B
});
I think the better solution is to keep only a single array in state to map over in the first place.
state = {
telephones: [], // { type: string, number: string }[]
}
...
state.telephones.map(({ type, number }, index) => {
// do stuff with telephone type
...
// do stuff with telephone number
});
If you also really want only a single change handler (I recommend they be separate), you can adopt a redux action/reducer type handler that accepts an object as a parameter that has all the data you need to update an array entry (index, update type, value). Here's a pretty clean example, but requires a bit of "action" setup when called:
changeHandler = (index, type) => e => {
const newTelephoneData = [...this.state.telephones];
newTelephoneData[index][type] = e.target.value;
this.setState({ telephones: newTelephoneData });
}
<select
value={type}
onChange={this.telephoneChangeHandler(index, "type")}
>
// options
</select>
...
<input
value={number}
onChange={this.telephoneChangeHandler(index, "number")}
placeholder={`Telephone No. #${index + 1}`}
/>
Below I've created a few working sandbox demos:
- Dual telephone data arrays, single change ("action/reducer") handler, separate add/remove functions, single map pass using index accessor to second array:
- Single telephone data array, single change handler, separate add/remove, single map pass:
- Use react
useReducer
, single array, reducer handles add/remove/update, single map pass:
I've included code documentation but if anything is unclear please let me know and I can clean up these demos.
回答2:
Yes, absolutely, something along:
telephone: {
list: [1,2,3],
type: [“foo”, “bar”, “baz”]
}
来源:https://stackoverflow.com/questions/56807902/react-nested-array