React, console.log 및 render는 다른 값을 표시합니다.
콘솔에 기록 된 객체 가 HTML에 표시된 것과 일치하지 않는 것 같습니다. 아래의 간단한 예제에 의아해합니다. 여기서 버튼은 배열의 순서를 토글하고 React는 이전 목록을 렌더링하는 것처럼 보입니다.
=== 업데이트 3 ====
cuprite는 setState(list=>list.push(12))목록을 변경하지만 목록의 ID가 여전히 동일하기 때문에 setState를 트리거하지 않는 객체 연민 입니다.
상태 후크를 현재 상태와 동일한 값으로 업데이트하면 React는 자식을 렌더링하거나 효과를 발생시키지 않고 구제 조치를 취합니다. (React는 Object.is 비교 알고리즘을 사용합니다.) React useState doc
=== 업데이트 2 ====
해결책을 찾은 것 같습니다. 범인은 객체의 변경 가능성 인 것으로 보이며 해결 방법은 Solution Sandbox 에서 정렬 된 목록의 깊은 복사본을 만드는 것 입니다. 나는 목록의 가변성은 어떤 차이가 발생할 안 이후로는, 반작용의 정의되지 않은 동작을 발견 생각 console.log(list)하고 <h1>list</h1>아래 그림. ReactJS의 상태 배열 수정 수정
=== 업데이트 1 ====
아래 표시된 것과 동일한 코드를 포함하는 샌드 박스 .
내 정렬 기능에 문제가 없습니다! 오름차순이면 더 작은 요소가 먼저 와야하므로 비교 함수 (e1,e2)=>e1-e2가 정확합니다.
compareFunction (a, b)가 0보다 작은 값을 반환하면 a를 b보다 낮은 인덱스로 정렬합니다 (즉, a가 먼저옵니다). 비교 함수 Mozilla
const {useState, useEffect, useReducer} = React;
function App() {
const [list, setList] = useState([0,1]);
const [isAscending, toggle] = useReducer(isAscending=>!isAscending, true);
// update the order of the list
useEffect(()=>{
if (isAscending) {
setList(list.sort((e1,e2)=>e1-e2));
} else {
setList(list.sort((e1,e2)=>e2-e1));
}
},[list, isAscending]);
// render
return (
<div>
{console.log("list[0] should be",list[0])}
<button onClick={toggle}>{isAscending?"Ascending":"Descending"}</button>
<h1>list[0]: {list[0]}</h1>
</div>
)
}
ReactDOM.render(<App/>, document.querySelector('.App'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div class='App'/>
답변
MDN 자바 스크립트 정렬 기능에 따라 배열을 변경합니다.
sort () 메서드는 배열 요소를 제자리에 정렬하고 정렬 된 배열을 반환합니다.
당신이 쓸 때 :
setList(list.sort((e1, e2) => e1 - e2));
setList를 변경하기 전에 목록을 변경하고 있습니다.
setList는 주어진 값이 이전과 다른지 확인한 다음 렌더링합니다.
그러나 setList는 목록 값이 이미 sort 메소드에 의해 업데이트 되었기 때문에 다르지 않습니다.
이로 인해 렌더링은 한 단계 뒤처진 것처럼 보입니다.
따라서 다음과 같이 작성해야합니다.
setList([...list].sort((e1, e2) => e1 - e2));
하나 더:
당신이 변해야한다고 생각합니다
{isAscending ? "Ascending" : "Descending"}
...에
{isAscending ? "Descending" : "Ascending"}
토글 버튼이기 때문에
초기 주문은 오름차순입니다. 버튼을 클릭하면 오름차순에서 내림차순으로 이동하려는 순서를 처음으로 전환합니다.
의미
if (isAscending) {
// Logic for descending should come here
setList(list.sort((e1, e2) => e2 - e1));
} else {
// Logic for ascending should come here
setList(list.sort((e1, e2) => e1 - e2));
}
여기에서 코드를 확인하고 이것이 당신이 찾고 있던 것인지 알려주세요. 코드 샌드 박스 : 정렬 된 목록이 렌더링되지 않음
콜백 에서 list값에 대한 클로저 가 있으므로 useEffectdep 배열에 추가해야합니다.
function App() {
const [list, setList] = useState([0, 1]);
const [isAscending, toggle] = useReducer((isAscending) => !isAscending, true);
useEffect(() => {
setList(list.sort((e1, e2) => (!isAscending ? e1 - e2 : e2 - e1)));
}, [list, isAscending]);
return (
<div>
<button onClick={toggle}>
{isAscending ? "Ascending" : "Descending"}
</button>
<pre>{JSON.stringify(list)}</pre>
</div>
);
}
만약 당신이
eslint그것에 대한 경고를 받아야한다는 점에 유의 하십시오.
https://codesandbox.io/s/react-template-forked-08eft?file=/index.js:99-684
스 니펫을 약간 단순화했습니다.
이상하게도 둘 다 사용 useState하고 useReducer있었고 두 번째는 첫 번째의 대안입니다.
useReducer는 일반적으로 여러 하위 값을 포함하는 복잡한 상태 논리가 있거나 다음 상태가 이전 상태에 종속 될 때 useState보다 선호됩니다.
Reactjs 문서 에서 인용
const {useReducer} = React;
function App() {
const list=[0,1]
const [isAscending, toggle] = useReducer(isAscending=>{
if (isAscending) {
list.sort((e1,e2)=>e2-e1)
} else {
list.sort((e1,e2)=>e1-e2)
}
return !isAscending
}, list);
// render
return (
<div>
{console.log("list[0] should be",list[0])}
<button onClick={toggle}>{isAscending?"Ascending":"Descending"}</button>
<h1>list[0]: {list[0]}</h1>
</div>
)
}
ReactDOM.render(<App/>, document.querySelector('.App'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div class='App'/>
그래서 여기 list는 IS initialState문서의 예. 그리고 목록을 재정렬하는 논리는 이제 정말 간단합니다. 리듀서 함수 안에 있습니다.
도움이되기를 바랍니다! ;)