排序组件的子组件状态未更新时



我有一个父组件,它的子组件需要按日期排序。我已经实现了对组件进行排序,但是这些组件有一个状态,当排序按钮被单击时保持固定。

的例子:

I have table

第一行{name: foo, date: 06/16/2022}第二行{name: bar, date:06/12/2022}

排序后

第一行{name: foo, date: 06/12/2022}第二行{name: bar, date: 06/16/2022}

名称保持不变,日期排序。

父组件

export default class RonusBows extends React.Component {
constructor(props) {
super(props);
this.state = {
bonus: [],
order: "asc",
};
this.sortFunction = this.sortFunction.bind(this);
}
state = {
bonus: [],
order: "asc",
};
componentDidMount() {
axios
.get(`http://localhost:4000/api/v1/process/creator/gutierad5`)
.then((res) => {
const bonus = res.data;
console.log(17, bonus);
this.setState({ bonus: bonus.processes });
});
}
sortFunction() {
if (this.state.order == "asc") {
this.setState(
this.state.bonus.sort((a, b) => {
const objectA = new Date(a.createdAt);
const objectB = new Date(b.createdAt);
return objectB.getTime() - objectA.getTime();
})
);
this.setState({ order: "desc" });
} else {
this.setState(
this.state.bonus.sort((a, b) => {
const objectA = new Date(a.createdAt);
const objectB = new Date(b.createdAt);
return objectA.getTime() - objectB.getTime();
})
);
this.setState({ order: "asc" });
}
}
render() {
return (
<ProcessTable funcionality={this.sortFunction}>
<Accordion allowToggle allowMultiple>
{this.state.bonus.map((element, index) => (
<AccordionItemSlot
key={index}
proccessID={element.id}
title={element.name}
targeruser='gutierad5'
createDate={FormatDateInYYMMDD(element.createdAt)}
status={element.status}
creator={element.creator}
links={element.links}
amount={element.processBonus.amount}
updatedAt={element.updatedAt}
password={element.processBonus.password}
franchise={element.processBonus.franchise}
/>
))}
</Accordion>
</ProcessTable>
);
}
}
**children component**
export type AccordionItemType = InputHTMLAttributes<HTMLInputElement> & {
title: string;
targeruser: string;
createDate: string;
creator?: string;
status: string;
links: Array<any>;
amount: string;
updatedAt: string;
password: string;
franchise: string;
proccessID: string;
};
export const AccordionItemSlot = (props: AccordionItemType) => {
const WarningString = `Please Click on Accept to see your price`;
const StateContext = React.createContext(props.status);
const [state, setState] = useState(props.status);
const handleChange = () => {
setState("Acknowledged");
};
return (
<StateContext.Provider value={state}>
<AccordionItem>
<h2>
<AccordionButton>
<Box flex='1'>
<ProcessRow
status={state}
title={props.title}
targeruser={props.targeruser}
createDate={props.createDate}
creator={"daniela"}
/>
</Box>
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
<HStack spacing='150px'>
<Box>
<List spacing={3}>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Title : {props.title}
</ListItem>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Creator : {props.creator}
</ListItem>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Created Date : {props.createDate.toString()}
</ListItem>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
{state === "Acknowledged" ? (
<a
href={checkIfHTTPSOrNot(props.links[0].URL)}
target='_blank'
rel='noopener'
>
Click here to check your prize <ExternalLinkIcon mx={2} />
</a>
) : (
WarningString
)}
</ListItem>
</List>
</Box>
<Box>
<List spacing={3}>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Amount : {props.amount} COP
</ListItem>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Password : {props.password}
</ListItem>
<ListItem>
<ListIcon as={BiCaretRight} color='green.500' />
Franchise : {props.franchise}
</ListItem>
<ListItem>
{state === "New" ? (
<ButtonComponent
colorScheme={"teal"}
variant={"solid"}
funcionality={() =>
requestForButton(
props.proccessID,
props.targeruser,
handleChange
)
}
size={"md"}
>
Accept
</ButtonComponent>
) : (
"👈🥳 You are ready to collect your prize!"
)}
</ListItem>
</List>
</Box>
</HStack>
</AccordionPanel>
</AccordionItem>
</StateContext.Provider>
);
};
export const AccordionWrapper = ({ children }: { children: ReactNode }) => {
<Accordion allowMultiple allowToggle>
{children}
</Accordion>;
};
```
Thanks in advanced, I'm very new to react and ts : P

Issue

问题是Array.prototype.sort对数组进行就地排序,并返回已排序的相同数组。

Array.prototype.sort

  1. 不要在React中改变状态
  2. React使用浅引用相等性检查作为调和过程的一部分,并且由于数组引用不会改变,React会放弃重新渲染。

解决方案当排队React状态更新时,你应该浅层复制所有状态,以及正在更新的嵌套状态。在对数组进行排序之前,创建一个数组的副本,以便对新数组进行排序。

的例子:

ascendingComparator = (a, b) => {
const objectA = new Date(a.createdAt);
const objectB = new Date(b.createdAt);
return objectB.getTime() - objectA.getTime();
}
descendingComparator = (a, b) => {
return ascendingComparator(b, a);
}
sortFunction = () => {
this.setState(state => ({
bonus: state.bonus
.slice() // <-- create new array
.sort(state.order == 'asc' // <-- select sort comparator
? ascendingComparator
: descendingComparator
),
order: state.order == 'asc' ? 'desc' : 'asc', // <-- toggle order
}));
}

一些数组方法,如Array.sort,直接改变内存中的数组,导致React不呈现组件,因为在排序后,原始数组和新数组之间没有实际的变化。

一般的经验法则是,当新的更改会影响组件的呈现时,避免对象或数组的变化。


function sortFunction() {
if (this.state.order == "asc") {
const sortedBonusAsc = [...this.state.bonus].sort((a, b) => {
const objectA = new Date(a.createdAt);
const objectB = new Date(b.createdAt);
return objectB.getTime() - objectA.getTime();
});
this.setState({ order: "desc", bonus: sortedBonusAsc });
} else {
const sortedBonusDesc = [...this.state.bonus].sort((a, b) => {
const objectA = new Date(a.createdAt);
const objectB = new Date(b.createdAt);
return objectA.getTime() - objectB.getTime();
});
this.setState({ order: "asc", bonus: sortedBonusDesc });
}
}

最新更新