Reputation: 3340
At the moment in my component I am setting the default value to 'null', but I am trying to default the active states value to the first object in the objects which is part of the state, a bit confused.
code so far:
import React from 'react';
interface ActiveObject {
id: number;
title: string;
function(index: number): void;
};
interface ButtonGroupState {
activeObject: ActiveObject | null;
objects: ActiveObject[];
};
const ButtonGroup: React.FunctionComponent = () => {
const [active, setActive] = React.useState<ButtonGroupState>({
activeObject: null,
objects: [{
id: 1,
title: '1 Week',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 2,
title: '1 Month',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 3,
title: '3 Months',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}]
})
const toggleActiveStyles = (index: number) => {
if (active.objects[index] === active.activeObject) {
return "btn-active"
} else {
return " btn-plain"
}
}
return (
<> <div className="wrapper">
{active.objects.map((inner, index) =>
<button type="button" className={toggleActiveStyles(index)} onClick={() => inner.function(index)} key={inner.id}>{inner.title}</button>
)}
</div>
</>
)
}
export default ButtonGroup;
Upvotes: 0
Views: 3248
Reputation: 202781
You can either duplicate the first element data as the initial state. Note: factoring the array definition out would be an optimization.
const ButtonGroup: React.FunctionComponent = () => {
const [active, setActive] = React.useState<ButtonGroupState>({
activeObject: {
id: 1,
title: '1 Week',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
},
objects: [{
id: 1,
title: '1 Week',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 2,
title: '1 Month',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 3,
title: '3 Months',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}]
});
or use an useEffect
hook to set it on the initial render.
React.useEffect(() => {
setActive(active[0]);
}, []);
You appear to have a logical bug with the functions where they will have stale enclosures the active
and activeObject
state. This may be ok for the active.object
if it's never updated. Since it's the same function for each element you should factor this out so your code is more DRY, and use a functional update.
You likely also don't what to duplicate state. Just store the active id (or index) and reference this in your code when accessing/passing props.
const setActive = (index: number) => {
setActive(active => ({
...active,
activeObject: index,
}));
}
Then use/pass setActive
as a prop where you need to.
...
activeObject={active.objects[active.activeObject]}
setActive={setActive}
...
Upvotes: 0
Reputation: 81
I suggest you move objects into a variable and set it's first element to activeObject
import React from 'react';
interface ActiveObject {
id: number;
title: string;
function(index: number): void;
};
interface ButtonGroupState {
activeObject: ActiveObject | null;
objects: ActiveObject[];
};
const ButtonGroup: React.FunctionComponent = () => {
const objectsArray = [{
id: 1,
title: '1 Week',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 2,
title: '1 Month',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}, {
id: 3,
title: '3 Months',
function(index: number) {
setActive({ ...active, activeObject: active.objects[index] })
}
}];
const [active, setActive] = React.useState<ButtonGroupState>({
activeObject: objectsArray[0],
objects: objectsArray
})
const toggleActiveStyles = (index: number) => {
if (active.objects[index] === active.activeObject) {
return "bp-active"
} else {
return " btn-plain"
}
}
return (
<> <div className="wrapper">
{active.objects.map((inner, index) =>
<button type="button" className={toggleActiveStyles(index)} onClick={() => inner.function(index)} key={inner.id}>{inner.title}</button>
)}
</div>
</>
)
}
export default ButtonGroup;
Upvotes: 1